diff --git a/Cargo.lock b/Cargo.lock
index a6600c07..17d77d11 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.21.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
 dependencies = [
  "gimli",
 ]
@@ -52,57 +52,58 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.4"
+version = "0.6.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
+checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
 dependencies = [
  "anstyle",
  "anstyle-parse",
  "anstyle-query",
  "anstyle-wincon",
  "colorchoice",
+ "is_terminal_polyfill",
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle"
-version = "1.0.4"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
+checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.2"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
+checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.0.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.1"
+version = "3.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
+checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
 dependencies = [
  "anstyle",
- "windows-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "async-trait"
-version = "0.1.77"
+version = "0.1.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
+checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -111,15 +112,15 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.1.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 
 [[package]]
 name = "backtrace"
-version = "0.3.69"
+version = "0.3.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11"
 dependencies = [
  "addr2line",
  "cc",
@@ -130,32 +131,44 @@ dependencies = [
  "rustc-demangle",
 ]
 
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
 [[package]]
 name = "bitflags"
-version = "1.3.2"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
 
 [[package]]
 name = "bumpalo"
-version = "3.14.0"
+version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "bytes"
-version = "1.5.0"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
 
 [[package]]
 name = "cc"
-version = "1.0.83"
+version = "1.0.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
+checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
 
 [[package]]
 name = "cfg-if"
@@ -165,23 +178,23 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.31"
+version = "0.4.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
  "js-sys",
  "num-traits",
  "wasm-bindgen",
- "windows-targets",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
 name = "clap"
-version = "4.4.8"
+version = "4.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
+checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -189,9 +202,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.4.8"
+version = "4.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
+checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
 dependencies = [
  "anstream",
  "anstyle",
@@ -201,9 +214,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.4.7"
+version = "4.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
+checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -213,50 +226,90 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.6.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
+checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
 
 [[package]]
 name = "colorchoice"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.4"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
 
 [[package]]
 name = "dns_rust"
 version = "0.1.0"
 dependencies = [
  "async-trait",
+ "base64",
  "bytes",
  "chrono",
  "clap",
  "futures-util",
  "hex",
+ "hmac",
  "lru",
- "rand",
+ "rand 0.8.5",
+ "rust-crypto",
+ "sha2",
  "thiserror",
  "tokio",
  "tokio-stream",
 ]
 
+[[package]]
+name = "fuchsia-cprng"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
+
 [[package]]
 name = "futures-core"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -265,15 +318,15 @@ dependencies = [
 
 [[package]]
 name = "futures-task"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
 
 [[package]]
 name = "futures-util"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
 dependencies = [
  "futures-core",
  "futures-macro",
@@ -283,28 +336,44 @@ dependencies = [
  "slab",
 ]
 
+[[package]]
+name = "gcc"
+version = "0.3.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
 [[package]]
 name = "getrandom"
-version = "0.2.11"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
 ]
 
 [[package]]
 name = "gimli"
-version = "0.28.0"
+version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
 
 [[package]]
 name = "hashbrown"
-version = "0.14.3"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 dependencies = [
  "ahash",
  "allocator-api2",
@@ -312,15 +381,15 @@ dependencies = [
 
 [[package]]
 name = "heck"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.3"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
 
 [[package]]
 name = "hex"
@@ -328,11 +397,20 @@ version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
 [[package]]
 name = "iana-time-zone"
-version = "0.1.58"
+version = "0.1.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
+checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -351,26 +429,32 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
+
 [[package]]
 name = "js-sys"
-version = "0.3.65"
+version = "0.3.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
 dependencies = [
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.150"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "lock_api"
-version = "0.4.11"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -378,9 +462,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.20"
+version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
 
 [[package]]
 name = "lru"
@@ -393,35 +477,35 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.6.4"
+version = "2.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
 dependencies = [
  "adler",
 ]
 
 [[package]]
 name = "mio"
-version = "0.8.9"
+version = "0.8.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
 dependencies = [
  "libc",
- "wasi",
- "windows-sys",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "num-traits"
-version = "0.2.17"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
 dependencies = [
  "autocfg",
 ]
@@ -438,24 +522,24 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.32.1"
+version = "0.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.18.0"
+version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
 name = "parking_lot"
-version = "0.12.1"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -463,22 +547,22 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.9"
+version = "0.9.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "pin-utils"
@@ -494,22 +578,45 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.76"
+version = "1.0.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "rand"
+version = "0.3.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
+dependencies = [
+ "libc",
+ "rand 0.4.6",
+]
+
+[[package]]
+name = "rand"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
+dependencies = [
+ "fuchsia-cprng",
+ "libc",
+ "rand_core 0.3.1",
+ "rdrand",
+ "winapi",
+]
+
 [[package]]
 name = "rand"
 version = "0.8.5"
@@ -518,7 +625,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
  "rand_chacha",
- "rand_core",
+ "rand_core 0.6.4",
 ]
 
 [[package]]
@@ -528,9 +635,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
+dependencies = [
+ "rand_core 0.4.2",
 ]
 
+[[package]]
+name = "rand_core"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
+
 [[package]]
 name = "rand_core"
 version = "0.6.4"
@@ -540,20 +662,48 @@ dependencies = [
  "getrandom",
 ]
 
+[[package]]
+name = "rdrand"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
 [[package]]
 name = "redox_syscall"
-version = "0.4.1"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
 dependencies = [
  "bitflags",
 ]
 
+[[package]]
+name = "rust-crypto"
+version = "0.2.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
+dependencies = [
+ "gcc",
+ "libc",
+ "rand 0.3.23",
+ "rustc-serialize",
+ "time",
+]
+
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "rustc-serialize"
+version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401"
 
 [[package]]
 name = "scopeguard"
@@ -561,11 +711,22 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
 [[package]]
 name = "signal-hook-registry"
-version = "1.4.1"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
 dependencies = [
  "libc",
 ]
@@ -581,31 +742,37 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.11.2"
+version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "socket2"
-version = "0.5.5"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "strsim"
-version = "0.10.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "subtle"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
 
 [[package]]
 name = "syn"
-version = "2.0.48"
+version = "2.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -614,29 +781,40 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.50"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.50"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
+[[package]]
+name = "time"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
+dependencies = [
+ "libc",
+ "wasi 0.10.0+wasi-snapshot-preview1",
+ "winapi",
+]
+
 [[package]]
 name = "tokio"
-version = "1.35.1"
+version = "1.38.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
+checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
 dependencies = [
  "backtrace",
  "bytes",
@@ -648,14 +826,14 @@ dependencies = [
  "signal-hook-registry",
  "socket2",
  "tokio-macros",
- "windows-sys",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.2.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
+checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -673,6 +851,12 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
 [[package]]
 name = "unicode-ident"
 version = "1.0.12"
@@ -681,9 +865,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "utf8parse"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
 name = "version_check"
@@ -691,6 +875,12 @@ version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -699,9 +889,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.88"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -709,9 +899,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.88"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
 dependencies = [
  "bumpalo",
  "log",
@@ -724,9 +914,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.88"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -734,9 +924,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.88"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -747,17 +937,39 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.88"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-core"
-version = "0.51.1"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -766,7 +978,16 @@ version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -775,13 +996,29 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.5",
+ "windows_aarch64_msvc 0.52.5",
+ "windows_i686_gnu 0.52.5",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.5",
+ "windows_x86_64_gnu 0.52.5",
+ "windows_x86_64_gnullvm 0.52.5",
+ "windows_x86_64_msvc 0.52.5",
 ]
 
 [[package]]
@@ -790,56 +1027,104 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
 [[package]]
 name = "windows_i686_gnu"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
 [[package]]
 name = "windows_i686_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+
 [[package]]
 name = "zerocopy"
-version = "0.7.32"
+version = "0.7.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.7.32"
+version = "0.7.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/Cargo.toml b/Cargo.toml
index ded60c37..05e94d48 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,6 +16,11 @@ tokio-stream = "0.1"
 thiserror = "1.0.20"
 futures-util = "0.3.28"
 async-trait = "0.1.77"
+sha2 = "0.10.2"
+hmac = "0.12.1"
+rust-crypto = "0.2"
+base64 = "0.22.1"
+
 lru = "0.12.3"
 
 [lib]
diff --git a/src/async_resolver.rs b/src/async_resolver.rs
index 01a93f52..12e66fd7 100644
--- a/src/async_resolver.rs
+++ b/src/async_resolver.rs
@@ -19,10 +19,13 @@ use crate::message::rcode::Rcode;
 use crate::message::rdata::Rdata;
 use crate::message::resource_record::ResourceRecord;
 use crate::message::rrtype::Rrtype;
+use crate::tsig;
 use crate::message::{self, DnsMessage};
 use crate::resolver_cache::ResolverCache;
 use std::net::IpAddr;
+use std::time::SystemTime;
 use std::sync::{Arc, Mutex};
+use std::vec;
 
 /// Asynchronous resolver for DNS queries.
 ///
@@ -105,10 +108,13 @@ impl AsyncResolver {
         let response = self
             .inner_lookup(domain_name_struct, Rrtype::A, rclass.into())
             .await;
-
+        
         return self
             .check_error_from_msg(response)
             .and_then(|lookup_response| {
+                if lookup_response.to_dns_msg().get_header().get_tc() {
+                    self.config.set_protocol(ConnectionProtocol::TCP);
+                }
                 let rrs_iter = lookup_response.to_vec_of_rr().into_iter();
                 let ip_addresses: Result<Vec<IpAddr>, _> = rrs_iter
                     .map(|rr| AsyncResolver::from_rr_to_ip(rr))
@@ -168,6 +174,11 @@ impl AsyncResolver {
                 Rclass::from(rclass),
             )
             .await;
+        
+        
+        if self.config.get_tsig(){
+            self.verify_tsig(response.clone());
+        }
 
         return self.check_error_from_msg(response);
     }
@@ -316,13 +327,13 @@ impl AsyncResolver {
     /// answer section, it is always preferred.
     fn store_data_cache(&self, response: DnsMessage) {
         let truncated = response.get_header().get_tc();
-        let rcode = response.get_header().get_rcode();
         {
             let mut cache = self.cache.lock().unwrap();
             cache.timeout();
             if !truncated {
                 cache.add(response.clone());
             }
+            
         }
     }
 
@@ -417,6 +428,44 @@ impl AsyncResolver {
             _ => Err(ClientError::ResponseError(rcode.into()))?,
         }
     }
+
+    /// Verifies tsig
+    pub fn verify_tsig(&self, 
+        response: Result<LookupResponse, ResolverError>)
+        -> Result<LookupResponse, ClientError> {
+        let lookup_response = match response {
+            Ok(val) => Ok(val),
+            Err(_) => Err(ClientError::TemporaryError("no DNS message found")),
+        };
+
+        let dns_response = lookup_response.unwrap().to_dns_msg();
+
+        let key_bytes = self.config.get_key();
+        let shared_key_name = self.config.get_key_name();
+        let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+        let algorithm = String::from(self.config.get_algorithm());
+        let alg_list = vec![(algorithm, true)];
+        let mac = dns_response.get_mac();
+
+        let (_val, rcode) = tsig::process_tsig(
+            &dns_response,
+            &key_bytes,
+            shared_key_name.clone().unwrap(),
+            time,
+            alg_list,
+            mac,
+        );
+
+        match rcode {
+            Rcode::NOERROR => Ok(LookupResponse::new(dns_response)),
+            Rcode::FORMERR => Err(ClientError::FormatError("The name server was unable to interpret the query."))?,
+            Rcode::SERVFAIL => Err(ClientError::ServerFailure("The name server was unable to process this query due to a problem with the name server."))?,
+            Rcode::NXDOMAIN => Err(ClientError::NameError("The domain name referenced in the query does not exist."))?,
+            Rcode::NOTIMP => Err(ClientError::NotImplemented("The name server does not support the requested kind of query."))?,
+            Rcode::REFUSED => Err(ClientError::Refused("The name server refuses to perform the specified operation for policy reasons."))?,
+            _ => Err(ClientError::ResponseError(rcode.into()))?,
+        }
+    }
 }
 
 // Getters
@@ -2009,7 +2058,6 @@ mod async_resolver_test {
 
         resolver.save_negative_answers(dns_response.clone());
 
-        let rrtype_search = Rrtype::A;
         assert_eq!(dns_response.get_answer().len(), 0);
         assert_eq!(dns_response.get_additional().len(), 1);
         assert_eq!(
diff --git a/src/async_resolver/config.rs b/src/async_resolver/config.rs
index 19c32359..ca21f939 100644
--- a/src/async_resolver/config.rs
+++ b/src/async_resolver/config.rs
@@ -1,8 +1,8 @@
 use crate::client::{udp_connection::ClientUDPConnection, tcp_connection::ClientTCPConnection,client_connection::ClientConnection };
 use crate::client::client_connection::ConnectionProtocol;
 use crate::message::DnsMessage;
+use crate::tsig::tsig_algorithm::TsigAlgorithm;
 use std::cmp::max;
-use std::option;
 use std::{net::{IpAddr,SocketAddr,Ipv4Addr}, time::Duration};
 
 use super::server_info::ServerInfo;
@@ -73,6 +73,14 @@ pub struct ResolverConfig {
     ends0_flags: u16,
     /// edns0 options for the resolver.
     ends0_options: Vec<u16>,
+    /// This is whether tsig is enabled or not.
+    tsig: bool,
+    /// This is the tsig keyname for the resolver.
+    key_name: Option<String>,
+    /// This is the tsig key for the resolver.
+    key: Vec<u8>,
+    /// algorithm for the tsig key
+    algorithm: TsigAlgorithm,
 }
 
 impl ResolverConfig {
@@ -113,6 +121,10 @@ impl ResolverConfig {
             ends0_version: 0,
             ends0_flags: 0,
             ends0_options: Vec::new(),
+            tsig: false,
+            key_name: None,
+            key: Vec::new(),
+            algorithm: TsigAlgorithm::HmacSha256,
         };
         resolver_config
     }
@@ -154,6 +166,10 @@ impl ResolverConfig {
             ends0_version: 0,
             ends0_flags: 0,
             ends0_options: Vec::new(),
+            tsig: false,
+            key_name: None,
+            key: Vec::new(),
+            algorithm: TsigAlgorithm::HmacSha256,
         };
         resolver_config
     }
@@ -245,6 +261,38 @@ impl ResolverConfig {
             message.add_edns0(Some(self.get_max_payload()), self.get_ends0_version(), self.get_ends0_flags(), Some(self.get_ends0_options()));
         }
     }
+
+    /// add tsig to the resolver
+    /// 
+    /// # Examples
+    /// ```
+    /// let mut resolver_config = ResolverConfig::default();
+    /// resolver_config.add_tsig("keyname".to_string(), b"key".to_vec(), Some(TsigAlgorithm::HmacSha256));
+    /// ```
+    pub fn add_tsig(&mut self, key_name: String, key: Vec<u8>, algorithm: Option<TsigAlgorithm>) {
+        self.tsig = true;
+        self.key_name = Some(key_name);
+        self.key = key;
+        if let Some(algorithm) = algorithm {
+            self.algorithm = algorithm;
+        }
+    }
+
+    /// add tsig from the resolver to a dns message
+    /// 
+    /// # Examples
+    /// ```
+    /// let mut resolver_config = ResolverConfig::default();
+    /// resolver_config.add_tsig("keyname".to_string(), b"key".to_vec(), Some(TsigAlgorithm::HmacSha256));
+    /// let message = Message::new();
+    /// resolver_config.add_tsig_to_message(&message, 300, vec![]);
+    /// ```
+    pub fn add_tsig_to_message(&self, message: &mut DnsMessage, fudge: Option<u16>, mac_request: Option<Vec<u8>>) {
+        if self.tsig {
+            message.add_tsig(self.key.clone(), self.algorithm.clone(), 
+            fudge.unwrap_or(300), self.key_name.clone(), mac_request.unwrap_or(Vec::new()));
+        }
+    }
 }
 
 ///Getters
@@ -317,6 +365,22 @@ impl ResolverConfig {
     pub fn get_ends0_options(&self) -> Vec<u16> {
         self.ends0_options.clone()
     }
+
+    pub fn get_tsig(&self) -> bool {
+        self.tsig
+    }
+
+    pub fn get_key_name(&self) -> Option<String> {
+        self.key_name.clone()
+    }
+
+    pub fn get_key(&self) -> Vec<u8> {
+        self.key.clone()
+    }
+
+    pub fn get_algorithm(&self) -> TsigAlgorithm {
+        self.algorithm.clone()
+    }
 }
 
 ///Setters
@@ -389,6 +453,22 @@ impl ResolverConfig{
     pub fn set_ends0_options(&mut self, ends0_options: Vec<u16>) {
         self.ends0_options = ends0_options;
     }
+
+    pub fn set_tsig(&mut self, tsig: bool) {
+        self.tsig = tsig;
+    }
+
+    pub fn set_key_name(&mut self, key_name: Option<String>) {
+        self.key_name = key_name;
+    }
+
+    pub fn set_key(&mut self, key: Vec<u8>) {
+        self.key = key;
+    }
+
+    pub fn set_algorithm(&mut self, algorithm: TsigAlgorithm) {
+        self.algorithm = algorithm;
+    }
 }
 
 
diff --git a/src/async_resolver/server_info.rs b/src/async_resolver/server_info.rs
index b6ab26cb..d0b10e99 100644
--- a/src/async_resolver/server_info.rs
+++ b/src/async_resolver/server_info.rs
@@ -12,6 +12,8 @@ pub struct ServerInfo {
     ip_addr: IpAddr,
     //The port of the server.
     port: u16,
+    //Tsig is enabled.
+    tsig: bool,
     //The key of the server.
     key: String,
     // The algorithm of the server.
@@ -29,6 +31,7 @@ impl ServerInfo {
         ServerInfo {
             ip_addr,
             port,
+            tsig: false,
             key,
             algorithm,
             udp_connection,
@@ -43,6 +46,7 @@ impl ServerInfo {
         ServerInfo {
             ip_addr,
             port,
+            tsig: false,
             key,
             algorithm,
             udp_connection,
@@ -59,6 +63,7 @@ impl ServerInfo {
         ServerInfo {
             ip_addr,
             port,
+            tsig: false,
             key,
             algorithm,
             udp_connection,
@@ -66,6 +71,16 @@ impl ServerInfo {
         }
     }
 
+    /// Function to enable tsig.
+    pub fn enable_tsig(&mut self) {
+        self.tsig = true;
+    }
+
+    /// Function to disable tsig.
+    pub fn disable_tsig(&mut self) {
+        self.tsig = false;
+    }
+
     /// Implements get_ip_address
     /// Returns IpAddr.
     pub fn get_ip_addr(&self) -> IpAddr {
@@ -88,6 +103,11 @@ impl ServerInfo {
         self.port = port;
     }
     
+    /// Get the tsig of the server.
+    pub fn get_tsig(&self) -> bool {
+        self.tsig
+    }
+
     /// Get the key of the server.
     pub fn get_key(&self) -> &str {
         &self.key
diff --git a/src/dns_cache.rs b/src/dns_cache.rs
index dc2de025..330547b4 100644
--- a/src/dns_cache.rs
+++ b/src/dns_cache.rs
@@ -43,7 +43,7 @@ impl DnsCache {
     pub fn new(max_size: Option<NonZeroUsize>) -> Self {
         let cache = DnsCache {
             cache: LruCache::new(max_size.unwrap_or_else(|| NonZeroUsize::new(1667).unwrap())),
-            max_size: max_size.unwrap_or_else(|| NonZeroUsize::new(100).unwrap()),
+            max_size: max_size.unwrap_or_else(|| NonZeroUsize::new(1667).unwrap()),
         };
         cache
     }
@@ -120,7 +120,7 @@ impl DnsCache {
     }
 
     /// Given a domain_name, gets an element from cache
-    pub fn get(&mut self, domain_name: DomainName, rrtype: Rrtype, rclass: Rclass) -> Option<Vec<RRStoredData>> {
+    pub fn get_primary(&mut self, domain_name: DomainName, rrtype: Rrtype, rclass: Rclass) -> Option<Vec<RRStoredData>> {
         let mut cache = self.get_cache();
 
         let rr_cache_vec = cache.get(&CacheKey::Primary(rrtype, rclass, domain_name)).cloned();
@@ -130,6 +130,23 @@ impl DnsCache {
         rr_cache_vec
     }
 
+    pub fn get_secondary(&mut self, domain_name: DomainName, rclass: Rclass)-> Option<Vec<RRStoredData>> {
+        let mut cache = self.get_cache();
+    
+        let rr_cache_vec = cache.get(&&CacheKey::Secondary(rclass, domain_name)).cloned();
+    
+        self.set_cache(cache);
+
+        rr_cache_vec
+    }
+
+    pub fn get(&mut self, domain_name: DomainName, rrtype: Option<Rrtype>, rclass: Rclass) -> Option<Vec<RRStoredData>> {
+        if rrtype != None {
+            return self.get_primary(domain_name, rrtype.unwrap(), rclass)
+        }
+        self.get_secondary(domain_name, rclass)
+    } 
+
     /// Removes the resource records from a domain name and type which were the oldest used
     pub fn remove_oldest_used(&mut self) {
         let mut cache = self.get_cache();
@@ -143,7 +160,7 @@ impl DnsCache {
     pub fn get_response_time(
         &mut self,
         domain_name: DomainName,
-        rrtype: Rrtype,
+        rrtype: Option<Rrtype>,
         rclass: Rclass,
         ip_address: IpAddr,
     ) -> u32 {
@@ -347,7 +364,7 @@ mod dns_cache_test {
 
         cache.add(domain_name.clone(), resource_record.clone(), Some(Rrtype::A), Rclass::IN, None);
 
-        let rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN).unwrap();
+        let rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN).unwrap();
 
         let first_rr_cache = rr_cache_vec.first().unwrap();
 
@@ -382,7 +399,7 @@ mod dns_cache_test {
 
         cache.add(domain_name.clone(), resource_record.clone(), Some(Rrtype::A), Rclass::IN, None);
 
-        let rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN).unwrap();
+        let rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN).unwrap();
 
         assert_eq!(rr_cache_vec.len(), 2);
     }
@@ -411,9 +428,9 @@ mod dns_cache_test {
 
         cache.add(domain_name.clone(), resource_record_2.clone(), Some(Rrtype::AAAA), Rclass::IN, None);
 
-        let rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN).unwrap();
+        let rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN).unwrap();
 
-        let rr_cache_vec_2 = cache.get(domain_name.clone(), Rrtype::AAAA, Rclass::IN).unwrap();
+        let rr_cache_vec_2 = cache.get(domain_name.clone(), Some(Rrtype::AAAA), Rclass::IN).unwrap();
 
         assert_eq!(rr_cache_vec.len(), 1);
         assert_eq!(rr_cache_vec_2.len(), 1);
@@ -443,7 +460,7 @@ mod dns_cache_test {
 
         cache.add(domain_name.clone(), resource_record.clone(), Some(Rrtype::A), Rclass::IN, None);
 
-        let rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN).unwrap();
+        let rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN).unwrap();
 
         assert_eq!(rr_cache_vec.len(), 1);
     }
@@ -464,7 +481,7 @@ mod dns_cache_test {
 
         cache.remove(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
 
-        let rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN);
+        let rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
 
         assert!(rr_cache_vec.is_none());
     }
@@ -483,7 +500,7 @@ mod dns_cache_test {
 
         cache.add(domain_name.clone(), resource_record.clone(), Some(Rrtype::A), Rclass::IN, None);
 
-        let rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN).unwrap();
+        let rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN).unwrap();
 
         let first_rr_cache = rr_cache_vec.first().unwrap();
 
@@ -508,7 +525,7 @@ mod dns_cache_test {
         let mut cache = DnsCache::new(NonZeroUsize::new(10));
         let domain_name = DomainName::new_from_str("example.com");
 
-        let rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN);
+        let rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
 
         assert!(rr_cache_vec.is_none());
     }
@@ -547,21 +564,21 @@ mod dns_cache_test {
         cache.add(domain_name_2.clone(), resource_record_2.clone(), Some(Rrtype::A), Rclass::IN, None);
         cache.add(domain_name_3.clone(), resource_record_3.clone(), Some(Rrtype::A), Rclass::IN, None);
 
-        let _rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN);
+        let _rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
 
-        let _rr_cache_vec_2 = cache.get(domain_name_2.clone(), Rrtype::A, Rclass::IN);
+        let _rr_cache_vec_2 = cache.get(domain_name_2.clone(), Some(Rrtype::A), Rclass::IN);
 
         cache.remove_oldest_used();
 
-        let rr_cache_vec = cache.get(domain_name_3.clone(), Rrtype::A, Rclass::IN);
+        let rr_cache_vec = cache.get(domain_name_3.clone(), Some(Rrtype::A), Rclass::IN);
 
         assert!(rr_cache_vec.is_none());
 
-        let rr_cache_vec_2 = cache.get(domain_name_2.clone(), Rrtype::A, Rclass::IN);
+        let rr_cache_vec_2 = cache.get(domain_name_2.clone(), Some(Rrtype::A), Rclass::IN);
 
         assert!(rr_cache_vec_2.is_some());
 
-        let rr_cache_vec_3 = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN);
+        let rr_cache_vec_3 = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
 
         assert!(rr_cache_vec_3.is_some());
     }
@@ -590,7 +607,7 @@ mod dns_cache_test {
 
         cache.set_cache(lru_cache);
 
-        let response_time_obtained = cache.get_response_time(domain_name.clone(), Rrtype::A, Rclass::IN, ip_address);
+        let response_time_obtained = cache.get_response_time(domain_name.clone(), Some(Rrtype::A), Rclass::IN, ip_address);
 
         assert_eq!(response_time_obtained, response_time);
     }
@@ -613,7 +630,7 @@ mod dns_cache_test {
 
         cache.update_response_time(domain_name.clone(), Rrtype::A, Rclass::IN, new_response_time, ip_address);
 
-        let response_time_obtained = cache.get_response_time(domain_name.clone(), Rrtype::A, Rclass::IN, ip_address);
+        let response_time_obtained = cache.get_response_time(domain_name.clone(), Some(Rrtype::A), Rclass::IN, ip_address);
 
         assert_eq!(response_time_obtained, new_response_time);
     }
@@ -718,11 +735,11 @@ mod dns_cache_test {
 
         assert!(!cache.is_empty());
 
-        let rr_cache_vec = cache.get(domain_name.clone(), Rrtype::A, Rclass::IN);
+        let rr_cache_vec = cache.get(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
 
         assert!(rr_cache_vec.is_none());
 
-        let rr_cache_vec_2 = cache.get(domain_name_2.clone(), Rrtype::A, Rclass::IN);
+        let rr_cache_vec_2 = cache.get(domain_name_2.clone(), Some(Rrtype::A), Rclass::IN);
 
         assert!(rr_cache_vec_2.is_some());
     }
diff --git a/src/dnssec.rs b/src/dnssec.rs
new file mode 100644
index 00000000..9f6c7239
--- /dev/null
+++ b/src/dnssec.rs
@@ -0,0 +1,4 @@
+pub mod dnssec_message;
+pub mod dnssec_message_processing;
+pub mod dnssec_fetch;
+pub mod rrset_signature;
\ No newline at end of file
diff --git a/src/dnssec/dnssec_fetch.rs b/src/dnssec/dnssec_fetch.rs
new file mode 100644
index 00000000..ccd090aa
--- /dev/null
+++ b/src/dnssec/dnssec_fetch.rs
@@ -0,0 +1,20 @@
+use crate::message::DnsMessage;
+use crate::message::rdata::Rdata;
+use crate::message::rdata::dnskey_rdata::DnskeyRdata;
+use crate::message::resource_record::ResourceRecord;
+use crate::dnssec::dnssec_message_processing::extract_dnssec_records;
+use crate::dnssec::rrset_signature::{verify_rrsig, verify_ds};
+
+use crate::client::client_error::ClientError;
+
+pub async fn fetch_dnskey_records(dns_response: &DnsMessage) -> Result<Vec<DnskeyRdata>, ClientError> {
+    let mut dnskey_records = Vec::new();
+
+    for record in dns_response.get_answer() {
+        if let Rdata::DNSKEY(dnskey) = &record.get_rdata() {
+            dnskey_records.push(dnskey.clone());
+        }
+    }
+
+    Ok(dnskey_records)
+}
diff --git a/src/dnssec/dnssec_message.rs b/src/dnssec/dnssec_message.rs
new file mode 100644
index 00000000..3f1b4b0c
--- /dev/null
+++ b/src/dnssec/dnssec_message.rs
@@ -0,0 +1,86 @@
+use std::str::FromStr;
+use crate::domain_name::DomainName;
+use crate::message::rclass::Rclass;
+use crate::message::DnsMessage;
+use crate::message::rdata::opt_rdata::OptRdata;
+use crate::message::rdata::Rdata;
+use crate::message::resource_record::{FromBytes, ResourceRecord, ToBytes};
+use crate::message::rcode;
+use crate::message::rcode::Rcode;
+use crate::message::rrtype::Rrtype;
+
+const EDNS_VERSION: u8 = 0;
+const REQUESTED_UDP_LEN: u16 = 4096;
+/*
+The mechanism chosen for the explicit notification of the ability of
+the client to accept (if not understand) DNSSEC security RRs is using
+the most significant bit of the Z field on the EDNS0 OPT header in
+the query.  This bit is referred to as the "DNSSEC OK" (DO) bit.  In
+the context of the EDNS0 OPT meta-RR, the DO bit is the first bit of
+the third and fourth bytes of the "extended RCODE and flags" portion
+of the EDNS0 OPT meta-RR, structured as follows:
+
+            +0 (MSB)                +1 (LSB)
+     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  0: |   EXTENDED-RCODE      |       VERSION         |
+     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  2: |DO|                    Z                       |
+     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+*/
+fn create_opt_rr(capacity: u16 ,e_rcode :u8, version: u8, do_bit: bool) -> ResourceRecord {
+    let opt_rdata = OptRdata::new();
+    let rdata = Rdata::OPT(opt_rdata);
+    let mut rr = ResourceRecord::new(rdata);
+
+    let do_val: u16 = if do_bit {0x8000} else {0x0};
+    let ttl: u32 = (e_rcode as u32) << 24 | (version as u32) << 16| (do_val as u32);
+    rr.set_ttl(ttl);
+    rr.set_rclass(Rclass::UNKNOWN(capacity));
+    println!("EL ttl es: {:#05x?}", ttl);
+    rr
+}
+
+fn read_opt_rr(opt_rr: ResourceRecord) -> String {
+    let requested_udp_len = Rclass::from(opt_rr.get_rclass());
+    let data = opt_rr.get_ttl().to_be_bytes();
+    let (e_rcode, version) = (data[0], data[1]);
+    let z = u16::from_be_bytes([data[2], data[3]]);
+
+    let do_bit = ((z & 0x8000) > 0) as u8 ;
+    format!("OPT PSEUDO-RR\n\trequested_udp_len: {requested_udp_len}\n\terror code: {e_rcode}\n\tversion: EDNS{version}\n\tuse dnssec: {do_bit}")
+}
+
+/*
+   A security-aware resolver MUST include an EDNS ([RFC2671]) OPT
+   pseudo-RR with the DO ([RFC3225]) bit set when sending queries.
+*/
+fn create_dns_message_with_dnssec(mut msg: DnsMessage) -> DnsMessage {
+    // We create a opt rr with the do bit set to 1
+    // with NOERR as rcode and EDNS0
+    let rr = create_opt_rr(REQUESTED_UDP_LEN,
+                            Rcode::from(Rcode::NOERROR).into(),
+                            EDNS_VERSION,
+                            true);
+
+    let vec = vec![rr];
+    msg.add_additionals(vec);
+    msg
+}
+
+#[test]
+fn see_dnssec_message() {
+    let query = DnsMessage::new_query_message(
+        DomainName::new_from_str("example.com"),
+        Rrtype::A,
+        Rclass::UNKNOWN(4096),
+        1,
+        true,
+        2000
+    );
+    let query= create_dns_message_with_dnssec(query);
+    assert_eq!(String::from_str
+                   ("OPT PSEUDO-RR\n\trequested_udp_len: 4096\n\terror code: 0\n\tversion: EDNS0\n\tuse dnssec: 1")
+                   .expect("Not a utf8 str"),
+               read_opt_rr(query.get_additional().pop().expect("No OPT Record!"))
+    )
+}
\ No newline at end of file
diff --git a/src/dnssec/dnssec_message_processing.rs b/src/dnssec/dnssec_message_processing.rs
new file mode 100644
index 00000000..8bbfff40
--- /dev/null
+++ b/src/dnssec/dnssec_message_processing.rs
@@ -0,0 +1,21 @@
+use crate::message::DnsMessage;
+use crate::message::rdata::Rdata;
+use crate::message::resource_record::ResourceRecord;
+
+pub fn extract_dnssec_records(dns_response: &DnsMessage) -> (Vec<ResourceRecord>, Vec<ResourceRecord>) {
+    let answers = dns_response.get_answer();
+    let additionals = dns_response.get_additional();
+
+    let mut dnskey_records = Vec::new();
+    let mut rrsig_records = Vec::new();
+
+    for record in answers.iter().chain(additionals.iter()) {
+        match record.get_rdata() {
+            Rdata::DNSKEY(_) => dnskey_records.push(record.clone()),
+            Rdata::RRSIG(_) => rrsig_records.push(record.clone()),
+            _ => {}
+        }
+    }
+
+    (dnskey_records, rrsig_records)
+}
diff --git a/src/dnssec/rrset_signature.rs b/src/dnssec/rrset_signature.rs
new file mode 100644
index 00000000..d7d75447
--- /dev/null
+++ b/src/dnssec/rrset_signature.rs
@@ -0,0 +1,72 @@
+use sha2::{Sha256, Digest};
+use crypto::digest::Digest as RustDigest;
+use crypto::sha1::Sha1;
+use base64::encode;
+use crate::message::rdata::Rdata;
+use crate::message::rdata::dnskey_rdata::DnskeyRdata;
+use crate::message::rdata::rrsig_rdata::RRSIGRdata;
+use crate::message::rrtype::Rrtype;
+use crate::message::resource_record::{ResourceRecord, ToBytes};
+use crate::client::client_error::ClientError;
+
+pub fn verify_rrsig(rrsig: &RRSIGRdata, dnskey: &DnskeyRdata, rrset: &[ResourceRecord]) -> Result<bool, ClientError> {
+    let mut rrsig_data = Vec::new();
+    rrsig_data.extend_from_slice(&u16::from(rrsig.get_type_covered()).to_be_bytes());
+    rrsig_data.push(rrsig.get_algorithm());
+    rrsig_data.push(rrsig.get_labels());
+    rrsig_data.extend_from_slice(&rrsig.get_original_ttl().to_be_bytes());
+    rrsig_data.extend_from_slice(&rrsig.get_signature_expiration().to_be_bytes());
+    rrsig_data.extend_from_slice(&rrsig.get_signature_inception().to_be_bytes());
+    rrsig_data.extend_from_slice(&rrsig.get_key_tag().to_be_bytes());
+    rrsig_data.extend_from_slice(&rrsig.get_signer_name().to_bytes());//Try?
+
+    let mut rrset_sorted = rrset.to_vec();
+    rrset_sorted.sort_by(|a, b| a.get_name().cmp(&b.get_name()));
+
+    for rr in rrset_sorted.iter() {
+        rrsig_data.extend_from_slice(&rr.get_name().to_bytes()); //Try?
+        rrsig_data.extend_from_slice(&rr.get_ttl().to_be_bytes());
+        rrsig_data.extend_from_slice(&(rr.get_rdata().to_bytes().len() as u16).to_be_bytes());
+        rrsig_data.extend_from_slice(&rr.get_rdata().to_bytes());//Try?
+    }
+
+    let signature = rrsig.get_signature().clone();
+    let hashed = Sha256::digest(&rrsig_data);
+
+    match dnskey.algorithm {
+        3 | 5 => {
+            // (DSA/RSA)/SHA1
+            let mut sha1 = Sha1::new();
+            sha1.input(&rrsig_data);
+            let digest = sha1.result_str();
+            Ok(digest == encode(&signature))
+        },
+        8 => {
+            // RSA/SHA256
+            Ok(encode(&hashed) == encode(&signature))
+        },
+        _ => Err(ClientError::NotImplemented("Unknown DNSKEY algorithm")),
+    }
+}
+
+pub fn verify_ds(ds_record: &ResourceRecord, dnskey: &DnskeyRdata) -> Result<bool, ClientError> {
+    if let Rdata::DS(ds_rdata) = &ds_record.get_rdata() {
+        let dnskey_bytes = dnskey.to_bytes();  //Try?
+        let hashed_key = match ds_rdata.algorithm {
+            1 => {
+                let mut hasher = Sha1::new();
+                hasher.input(&dnskey_bytes);
+                hasher.result_str()
+            },
+            2 => {
+                let hashed = Sha256::digest(&dnskey_bytes);
+                encode(&hashed)
+            },
+            _ => return Err(ClientError::NotImplemented("Unknown DS algorithm")),
+        };
+
+        Ok(ds_rdata.digest == hashed_key.as_bytes())
+    } else {
+        Err(ClientError::FormatError("Provided record is not a DS record"))
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 0a2f1a87..cff3be71 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,7 +5,5 @@ pub mod domain_name;
 pub mod message;
 pub mod async_resolver;
 pub mod truncated_dns_message;
-
-
-
-
+pub mod tsig;
+pub mod dnssec;
\ No newline at end of file
diff --git a/src/message.rs b/src/message.rs
index d2c78262..1efcdd9d 100644
--- a/src/message.rs
+++ b/src/message.rs
@@ -15,12 +15,15 @@ use crate::message::question::Question;
 use crate::message::resource_record::ResourceRecord;
 use crate::message::rdata::Rdata;
 use crate::message::rdata::opt_rdata::OptRdata;
+use crate::tsig;
+use crate::tsig::tsig_algorithm::TsigAlgorithm;
 use crate::message::rdata::opt_rdata::option_code::OptionCode;
 use rand::thread_rng;
 use rand::Rng;
 use resource_record::ToBytes;
 use core::fmt;
 use std::vec::Vec;
+use std::time::SystemTime;
 
 #[derive(Clone)]
 /// Structs that represents a DNS message.
@@ -286,6 +289,51 @@ impl DnsMessage {
         self.update_header_counters();
     }
 
+    /// Adds Tsig to the message.
+    /// 
+    /// # Example
+    /// ```
+    /// let dns_query_message = new_query_message(DomainName::new_from_str("example.com".to_string()), Rrtype::A, Rclass:IN, 0, false);
+    /// let key = vec![1, 2, 3, 4, 5, 6, 7, 8];
+    /// let alg_name = TsigAlgorithm::HmacSha1;
+    /// let fudge = 300;
+    /// let key_name = "key".to_string();
+    /// let mac_request = vec![];
+    /// dns_query_message.add_tsig(key, alg_name, fudge, key_name, mac_request);
+    /// ```
+    pub fn add_tsig(&mut self, key: Vec<u8>, alg_name: TsigAlgorithm, 
+        fudge: u16, key_name: Option<String>, mac_request: Vec<u8>) {
+        let message = self;
+        let time_signed = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+        tsig::sign_tsig(message, &key, alg_name, 
+                                        fudge, time_signed, key_name.unwrap_or("".to_string()), mac_request);
+    }
+
+    /// Gets the MAC from the TSIG RR.
+    /// 
+    /// # Example
+    /// ```
+    /// let dns_query_message = new_query_message(DomainName::new_from_str("example.com".to_string()), Rrtype::A, Rclass:IN, 0, false);
+    /// let key = vec![1, 2, 3, 4, 5, 6, 7, 8];
+    /// let alg_name = TsigAlgorithm::HmacSha1;
+    /// let fudge = 300;
+    /// let key_name = "key".to_string();
+    /// let mac_request = vec![];
+    /// dns_query_message.add_tsig(key, alg_name, fudge, key_name, mac_request);
+    /// let mac = dns_query_message.get_mac();
+    /// ```
+    pub fn get_mac(&self) -> Vec<u8> {
+        let mut mac = Vec::new();
+        let additional = self.get_additional();
+
+        for rr in additional {
+            if let Rdata::TSIG(tsig_rdata) = rr.get_rdata() {
+                mac = tsig_rdata.get_mac();
+            }
+        }
+
+        mac
+    }
 
     /// Creates a new axfr query message.
     /// 
@@ -615,6 +663,7 @@ impl DnsMessage {
         let mut msg_answers = self.get_answer();
 
         msg_answers.append(&mut answers);
+        self.header.set_ancount(msg_answers.len() as u16);
         self.set_answer(msg_answers);
     }
 
@@ -640,6 +689,7 @@ impl DnsMessage {
         let mut msg_authorities = self.get_authority();
 
         msg_authorities.append(&mut authorities);
+        self.header.set_nscount(msg_authorities.len() as u16);
         self.set_answer(msg_authorities);
     }
 
@@ -656,6 +706,7 @@ impl DnsMessage {
         let mut msg_additionals = self.get_additional();
 
         msg_additionals.append(&mut additionals);
+        self.header.set_arcount(msg_additionals.len() as u16);
         self.set_additional(msg_additionals);
     }
 
@@ -683,14 +734,17 @@ impl DnsMessage {
 impl fmt::Display for DnsMessage {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let mut result = String::new();
+        let question = self.get_question();
         let answers = self.get_answer().into_iter();
         let authority = self.get_authority().into_iter();
         let additional = self.get_additional().into_iter();
-        result.push_str(&format!("Answer\n"));
+        result.push_str(&format!("Question section\n"));
+        result.push_str(&format!("{}\n", question));
+        result.push_str(&format!("Answer section\n"));
         answers.for_each(|answer| result.push_str(&format!("{}\n", answer)));
-        result.push_str(&format!("Authority\n"));
+        result.push_str(&format!("Authority section\n"));
         authority.for_each(|authority| result.push_str(&format!("{}\n", authority)));
-        result.push_str(&format!("Additional\n"));
+        result.push_str(&format!("Additional section\n"));
         additional.for_each(|additional| result.push_str(&format!("{}\n", additional)));
         write!(f, "{}", result)
     }
@@ -984,7 +1038,7 @@ mod message_test {
         */
         let bytes: [u8; 50] = [
             //test passes with this one
-            0b00100100, 0b10010101, 0b10010010, 0b00000000, 0, 1, 0b00000000, 1, 0, 0, 0, 0, 4, 116,
+            0b00100100, 0b10010101, 0b10010010, 0b00100000, 0, 1, 0b00000000, 1, 0, 0, 0, 0, 4, 116,
             101, 115, 116, 3, 99, 111, 109, 0, 0, 16, 0, 1, 3, 100, 99, 99, 2, 99, 108, 0, 0, 16, 0,
             1, 0, 0, 0b00010110, 0b00001010, 0, 6, 5, 104, 101, 108, 108, 111,
         ];
@@ -1002,7 +1056,10 @@ mod message_test {
         assert_eq!(header.get_qr(), true);
         assert_eq!(header.get_op_code(), 2);
         assert_eq!(header.get_tc(), true);
+
+        assert_eq!(header.get_ad(), true);
         assert_eq!(header.get_rcode(), Rcode::NOERROR);
+
         assert_eq!(header.get_ancount(), 1);
 
         // Question
@@ -1041,7 +1098,10 @@ mod message_test {
         header.set_qr(true);
         header.set_op_code(2);
         header.set_tc(true);
+
+        header.set_ad(true);
         header.set_rcode(Rcode::UNKNOWN(8));
+
         header.set_ancount(0b0000000000000001);
         header.set_qdcount(1);
 
@@ -1081,7 +1141,7 @@ mod message_test {
         let msg_bytes = &dns_msg.to_bytes();
 
         let real_bytes: [u8; 50] = [
-            0b00100100, 0b10010101, 0b10010010, 0b00001000, 0, 1, 0b00000000, 0b00000001, 0, 0, 0,
+            0b00100100, 0b10010101, 0b10010010, 0b00101000, 0, 1, 0b00000000, 0b00000001, 0, 0, 0,
             0, 4, 116, 101, 115, 116, 3, 99, 111, 109, 0, 0, 5, 0, 2, 3, 100, 99, 99, 2, 99, 108,
             0, 0, 16, 0, 1, 0, 0, 0b00010110, 0b00001010, 0, 6, 5, 104, 101, 108, 108, 111,
         ];
diff --git a/src/message/header.rs b/src/message/header.rs
index 4e2b60dc..0d9b6c9b 100644
--- a/src/message/header.rs
+++ b/src/message/header.rs
@@ -3,22 +3,23 @@ use crate::message::rcode::Rcode;
 #[derive(Default, Clone)]
 
 ///  An struct that represents a Header secction from a DNS message.
-/// 
-///                                 1  1  1  1  1  1
-///   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
-///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-///  |                      ID                       |
-///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-///  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
-///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-///  |                    QDCOUNT                    |
-///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-///  |                    ANCOUNT                    |
-///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-///  |                    NSCOUNT                    |
-///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-///  |                    ARCOUNT                    |
-///  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+///  EDIT: now added bits AD CD for DNS security extensions.
+///
+///                                1  1  1  1  1  1
+///  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+/// |                      ID                       |
+/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+/// |QR|   Opcode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
+/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+/// |                    QDCOUNT                    |
+/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+/// |                    ANCOUNT                    |
+/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+/// |                    NSCOUNT                    |
+/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+/// |                    ARCOUNT                    |
+/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 #[derive (PartialEq, Debug)]
 pub struct Header {
     /// Id
@@ -40,10 +41,12 @@ pub struct Header {
     tc: bool, // TrunCation
     rd: bool, // Recursion Desired
     ra: bool, // Recursion Available
+    ad: bool, // Authentic Data
+    cd: bool, // Checking Disabled 
 
-    /// Reserved
+    /// Reserved Edit: Now z is just a flag
     #[allow(dead_code)]
-    z: u8,
+    z: bool,
 
     /// Response Code
     /// 
@@ -137,7 +140,11 @@ impl Header {
         let tc = (bytes[2] & 0b00000010) >> 1;
         let rd = bytes[2] & 0b00000001;
         let ra = bytes[3] >> 7;
+
+        let ad = (bytes[3] & 0b00100000) >> 5;
+        let cd = (bytes[3] & 0b00010000) >> 4;
         let rcode = Rcode::from(bytes[3] & 0b00001111);
+
         let qdcount = ((bytes[4] as u16) << 8) | bytes[5] as u16;
         let ancount = ((bytes[6] as u16) << 8) | bytes[7] as u16;
         let nscount = ((bytes[8] as u16) << 8) | bytes[9] as u16;
@@ -151,6 +158,8 @@ impl Header {
         header.set_tc(tc != 0);
         header.set_rd(rd != 0);
         header.set_ra(ra != 0);
+        header.set_ad(ad != 0);
+        header.set_cd(cd != 0);
         header.set_rcode(rcode);
         header.set_qdcount(qdcount);
         header.set_ancount(ancount);
@@ -209,7 +218,7 @@ impl Header {
             return 0b00000100;
         }
 
-        return 0 as u8;
+        return 0u8;
     }
 
     /// Returns a byte that represents the field in the DNS message.
@@ -222,7 +231,7 @@ impl Header {
             return 0b00000010;
         }
 
-        return 0 as u8;
+        return 0u8;
     }
 
     /// Returns a byte that represents the field in the DNS message.
@@ -235,7 +244,7 @@ impl Header {
             return 0b00000001;
         }
 
-        return 0 as u8;
+        return 0u8;
     }
 
     /// Returns a byte that represents the field in the DNS message.
@@ -248,7 +257,33 @@ impl Header {
             return 0b10000000;
         }
 
-        return 0 as u8;
+        return 0u8;
+    }
+
+    /// Returns a byte that represents the field in the DNS message.
+    ///
+    /// See the DNS message structure in struct documentation for more info.
+    fn ad_to_byte(&self) -> u8 {
+        let ad = self.get_ad();
+
+        if ad {
+            return 0b00100000;
+        }
+
+        return 0u8;
+    }
+
+    /// Returns a byte that represents the field in the DNS message.
+    ///
+    /// See the DNS message structure in struct documentation for more info.
+    fn cd_to_byte(&self) -> u8 {
+        let cd = self.get_cd();
+
+        if cd {
+            return 0b00010000;
+        }
+
+        return 0u8;
     }
 
     /// Gets the first byte from the qdcount attribute.
@@ -331,9 +366,13 @@ impl Header {
     /// Gets a byte that represents the second byte of flags section.
     fn get_second_flags_byte(&self) -> u8 {
         let ra_byte = self.ra_to_byte();
+
+        let ad_byte = self.ad_to_byte();
+        let cd_byte = self.cd_to_byte();
         let rcode_byte = u8::from(self.get_rcode());
 
-        let second_byte = ra_byte | rcode_byte;
+
+        let second_byte = ra_byte | ad_byte | cd_byte |  rcode_byte;
 
         second_byte
     }
@@ -382,7 +421,7 @@ impl Header {
         header_bytes
     }
 
-    /// Checks if the header is well formed.
+    /// Checks if the header is well-formed.
     pub fn format_check(&self)-> Result<bool, &'static str>{
 
         // OP CODE: A four bit field between 0-15 
@@ -390,8 +429,8 @@ impl Header {
             return Err("Format Error: OP CODE");
         }
 
-        // Z: A 3 bit field that MUST be zero 
-        if self.z != 0 {
+        // Z: A z flag field MUST be zero/false
+        if self.z != false {
             return Err("Format Error: Z");
         }
 
@@ -441,6 +480,16 @@ impl Header {
         self.ra = ra;
     }
 
+    /// Sets the ad attribute with a value.
+    pub fn set_ad(&mut self, ad: bool) {
+        self.ad = ad;
+    }
+
+    /// Sets the cd attribute with a value.
+    pub fn set_cd(&mut self, cd: bool) {
+        self.cd = cd;
+    }
+
     /// Sets the rcode attribute with a value.
     pub fn set_rcode(&mut self, rcode: Rcode) {
         self.rcode = rcode;
@@ -504,6 +553,16 @@ impl Header {
         self.ra
     }
 
+    /// Gets the ad attribute value.
+    pub fn get_ad(&self) -> bool {
+        self.ad
+    }
+
+    /// Gets the cd attribute value.
+    pub fn get_cd(&self) -> bool {
+        self.cd
+    }
+
     /// Gets the `rcode` attribute value.
     pub fn get_rcode(&self) -> Rcode {
         self.rcode
@@ -546,7 +605,11 @@ mod header_test {
         assert_eq!(header.tc, false);
         assert_eq!(header.rd, false);
         assert_eq!(header.ra, false);
+
+        assert_eq!(header.ad, false);
+        assert_eq!(header.cd, false);
         assert_eq!(header.rcode, Rcode::NOERROR);
+
         assert_eq!(header.qdcount, 0);
         assert_eq!(header.ancount, 0);
         assert_eq!(header.nscount, 0);
@@ -637,6 +700,30 @@ mod header_test {
         assert_eq!(ra, true);
     }
 
+    #[test]
+    fn set_and_get_ad() {
+        let mut header = Header::new();
+
+        let mut ad = header.get_ad();
+        assert_eq!(ad, false);
+
+        header.set_ad(true);
+        ad = header.get_ad();
+        assert_eq!(ad, true);
+    }
+
+    #[test]
+    fn set_and_get_cd() {
+        let mut header = Header::new();
+
+        let mut cd = header.get_cd();
+        assert_eq!(cd, false);
+
+        header.set_cd(true);
+        cd = header.get_cd();
+        assert_eq!(cd, true);
+    }
+
     #[test]
     fn set_and_get_rcode() {
         let mut header = Header::new();
@@ -708,13 +795,17 @@ mod header_test {
         header.set_qr(true);
         header.set_op_code(2);
         header.set_tc(true);
+
+        header.set_ad(true);
+        header.set_cd(true);
         header.set_rcode(Rcode::REFUSED);
+
         header.set_ancount(0b0000101010100101);
 
         bytes[0] = 0b00100100;
         bytes[1] = 0b10010101;
         bytes[2] = 0b10010010;
-        bytes[3] = 0b00000101;
+        bytes[3] = 0b00110101;
         bytes[6] = 0b00001010;
         bytes[7] = 0b10100101;
 
@@ -728,7 +819,7 @@ mod header_test {
         bytes[0] = 0b00100100;
         bytes[1] = 0b10010101;
         bytes[2] = 0b10010010;
-        bytes[3] = 0b00000101;
+        bytes[3] = 0b00110101;
         bytes[6] = 0b00001010;
         bytes[7] = 0b10100101;
 
@@ -738,7 +829,11 @@ mod header_test {
         header.set_qr(true);
         header.set_op_code(2);
         header.set_tc(true);
+
+        header.set_ad(true);
+        header.set_cd(true);
         header.set_rcode(Rcode::REFUSED);
+
         header.set_ancount(0b0000101010100101);
 
         let header_from_bytes = Header::from_bytes(&bytes);
@@ -790,8 +885,10 @@ mod header_test {
         ];
 
         let mut header = Header::from_bytes(&bytes_header);
-        header.z = 3;
+
+        header.z = true;
         header.set_rcode(Rcode::UNKNOWN(16));
+
         header.set_op_code(22);
 
         let result_check = header.format_check();
diff --git a/src/message/question.rs b/src/message/question.rs
index af445d7a..bc9f4cd5 100644
--- a/src/message/question.rs
+++ b/src/message/question.rs
@@ -4,6 +4,8 @@ use crate::message::rclass::Rclass;
 
 use super::rrtype::Rrtype;
 
+use std::fmt;
+
 #[derive(Default, Clone)]
 /// An struct that represents the question section from a dns message
 /// ```text
@@ -29,6 +31,20 @@ pub struct Question {
     rclass: Rclass,
 }
 
+
+impl fmt::Display for Question {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let name = self.get_qname().get_name();
+        let rtype = self.get_rrtype();
+        let rclass = self.get_rclass();
+                                                                                                  
+        formatter.write_fmt(format_args!(
+            "{}  {}  {} ",
+            name, rclass, rtype
+        ))
+    }
+}
+
 // Methods
 impl Question {
     /// Creates a new Question with default values
diff --git a/src/message/rcode.rs b/src/message/rcode.rs
index 91d3d036..a4f5d1d3 100644
--- a/src/message/rcode.rs
+++ b/src/message/rcode.rs
@@ -11,6 +11,9 @@ pub enum Rcode {
     NXDOMAIN,
     NOTIMP,
     REFUSED,
+    BADSIG,
+    BADKEY,
+    BADTIME,
     UNKNOWN(u8),
 }
 
@@ -23,6 +26,9 @@ impl From<u8> for Rcode {
             3 => Rcode::NXDOMAIN,
             4 => Rcode::NOTIMP,
             5 => Rcode::REFUSED,
+            16 => Rcode::BADSIG,
+            17 => Rcode::BADKEY,
+            18 => Rcode::BADTIME,
             _ => Rcode::UNKNOWN(int),
         }
     }
@@ -37,6 +43,9 @@ impl From<Rcode> for u8 {
             Rcode::NXDOMAIN => 3,
             Rcode::NOTIMP => 4,
             Rcode::REFUSED => 5,
+            Rcode::BADSIG => 16,
+            Rcode::BADKEY => 17,
+            Rcode::BADTIME => 18,
             Rcode::UNKNOWN(u8) => u8,
         }
     }
@@ -69,6 +78,9 @@ impl fmt::Display for Rcode {
             Rcode::NXDOMAIN => "NXDOMAIN",
             Rcode::NOTIMP => "NOTIMP",
             Rcode::REFUSED => "REFUSED",
+            Rcode::BADSIG => "BADSIG",
+            Rcode::BADKEY => "BADKEY",
+            Rcode::BADTIME => "BADTIME",
             Rcode::UNKNOWN(_) => "UNKNOWN",
         })
     }
diff --git a/src/message/rdata.rs b/src/message/rdata.rs
index c186c080..f057bd18 100644
--- a/src/message/rdata.rs
+++ b/src/message/rdata.rs
@@ -589,11 +589,33 @@ mod resolver_query_tests {
     #[test]
     fn to_bytes_tsigrdata(){
         let expected_bytes = vec![
-        0x8, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x6D, 0x64,
-        0x35, 0x7, 0x73, 0x69, 0x67, 0x2D, 0x61, 0x6C, 0x67,
-        0x3, 0x72, 0x65, 0x67, 0x3, 0x69, 0x6E, 0x74, 0x0, 0x0, 0x0, 0x0,
-        0x0, 0x7, 0x5B, 0xCD, 0x15, 0x4, 0xD2, 0x0, 0x4, 0xA1, 0xB2, 0xC3, 0xD4,
-        0x4, 0xD2, 0x0, 0x0, 0x0, 0x0
+            //This is the string "hmac-md5.sig-alg.reg.int" in octal, terminated in 00
+            0x8, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x6D, 0x64,
+            0x35, 0x7, 0x73, 0x69, 0x67, 0x2D, 0x61, 0x6C, 0x67,
+            0x3, 0x72, 0x65, 0x67, 0x3, 0x69, 0x6E, 0x74, 0x0,
+
+            //this is the time signed 123456789 == 0x75bcd15
+            0x0, 0x0, 0x7, 0x5B, 0xCD, 0x15,
+
+            // this the fudge 1234
+            0x4, 0xD2,
+
+            // this is the macsize = 4
+            0x0, 0x4,
+
+            // this is the mac = [0xA1, 0xB2, 0xC3, 0xD4]
+            0xA1, 0xB2, 0xC3, 0xD4,
+
+            // this is the original id = 1234
+            0x4, 0xD2,
+
+            // this is the error = 0
+            0x0, 0x0,
+
+            // this is the other len = 0
+            0x0, 0x0
+
+            // No other data, so its empty!
         ];
 
         let mut tsig_rdata = TSigRdata::new();
@@ -932,11 +954,34 @@ mod resolver_query_tests {
     #[test]
     fn from_bytes_tsig_rdata(){
         let data_bytes = vec![
-        0x8, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x6D, 0x64,
-        0x35, 0x7, 0x73, 0x69, 0x67, 0x2D, 0x61, 0x6C, 0x67,
-        0x3, 0x72, 0x65, 0x67, 0x3, 0x69, 0x6E, 0x74, 0x0, 0x0, 0x0, 0x0,
-        0x0, 0x7, 0x5B, 0xCD, 0x15, 0x4, 0xD2, 0x0, 0x4, 0xA1, 0xB2, 0xC3, 0xD4,
-        0x4, 0xD2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFA, 0x0, 0x1
+            //This is the string "hmac-md5.sig-alg.reg.int" in octal, terminated in 00
+            0x8, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x6D, 0x64,
+            0x35, 0x7, 0x73, 0x69, 0x67, 0x2D, 0x61, 0x6C, 0x67,
+            0x3, 0x72, 0x65, 0x67, 0x3, 0x69, 0x6E, 0x74, 0x0,
+
+            //this is the time signed 123456789 == 0x75bcd15
+            0x0, 0x0, 0x7, 0x5B, 0xCD, 0x15,
+
+            // this the fudge 1234
+            0x4, 0xD2,
+
+            // this is the macsize = 4
+            0x0, 0x4,
+
+            // this is the mac = [0xA1, 0xB2, 0xC3, 0xD4]
+            0xA1, 0xB2, 0xC3, 0xD4,
+
+            // this is the original id = 1234
+            0x4, 0xD2,
+
+            // this is the error = 0
+            0x0, 0x0,
+
+            // this is the other len = 0
+            0x0, 0x0,
+            //Extra bytes for from_bytes function
+            0x0, 0xFA, 0x0, 0x1
+            // No other data, so its empty!
         ];
         let rdata = Rdata::from_bytes(&data_bytes, &data_bytes).unwrap();
         let mut domain_name = DomainName::new();
diff --git a/src/message/rdata/opt_rdata.rs b/src/message/rdata/opt_rdata.rs
index ce394dec..1c2b0fae 100644
--- a/src/message/rdata/opt_rdata.rs
+++ b/src/message/rdata/opt_rdata.rs
@@ -53,6 +53,7 @@ impl FromBytes<Result<Self, &'static str>> for OptRdata {
                 return Err("Format Error");
             }
 
+
             let option_code = OptionCode::from(u16::from_be_bytes([bytes[i], bytes[i + 1]]));
             let option_length = u16::from_be_bytes([bytes[i + 2], bytes[i + 3]]);
 
diff --git a/src/message/rdata/tsig_rdata.rs b/src/message/rdata/tsig_rdata.rs
index 179d759d..6519cc05 100644
--- a/src/message/rdata/tsig_rdata.rs
+++ b/src/message/rdata/tsig_rdata.rs
@@ -67,10 +67,6 @@ impl ToBytes for TSigRdata{
         
         let time_signed = self.get_time_signed();
 
-        bytes.push((time_signed >> 56) as u8);
-
-        bytes.push((time_signed >> 48) as u8);
-
         bytes.push((time_signed >> 40) as u8);
 
         bytes.push((time_signed >> 32) as u8);
@@ -78,6 +74,10 @@ impl ToBytes for TSigRdata{
         bytes.push((time_signed >> 24) as u8);
 
         bytes.push((time_signed >> 16) as u8);
+
+        bytes.push((time_signed >> 8) as u8);
+
+        bytes.push((time_signed >> 0) as u8);
         
         let fudge = self.get_fudge();
 
@@ -255,14 +255,14 @@ impl TSigRdata {
 
     /// Set the time signed attribute from an array of bytes.
     fn set_time_signed_from_bytes(&mut self, bytes: &[u8]){
-        let time_signed = (bytes[0] as u64) << 56 
-                                | (bytes[1] as u64) << 48 
-                                | (bytes[2] as u64) << 40 
-                                | (bytes[3] as u64) << 32 
-                                | (bytes[4] as u64) << 24 
-                                | (bytes[5] as u64) << 16 
-                                | (0 as u64) << 8 
-                                | 0 as u64;
+
+        let time_signed = (bytes[0] as u64) << 40
+                                | (bytes[1] as u64) << 32 
+                                | (bytes[2] as u64) << 24 
+                                | (bytes[3] as u64) << 16 
+                                | (bytes[4] as u64) << 8 
+                                | (bytes[5] as u64) << 0;
+
         self.set_time_signed(time_signed);
     }
 
@@ -561,7 +561,6 @@ mod tsig_rdata_test {
     }
 
     #[test]
-    #[ignore = "Fix test"]
     fn to_bytes_test(){
         let mut tsig_rdata = TSigRdata::new();
 
@@ -580,11 +579,33 @@ mod tsig_rdata_test {
         let bytes_to_test = tsig_rdata.to_bytes();
 
         let bytes = vec![
-        0x8, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x6D, 0x64,
-        0x35, 0x7, 0x73, 0x69, 0x67, 0x2D, 0x61, 0x6C, 0x67,
-        0x3, 0x72, 0x65, 0x67, 0x3, 0x69, 0x6E, 0x74, 0x0, 0x0, 0x0, 0x0,
-        0x0, 0x7, 0x5B, 0xCD, 0x15, 0x4, 0xD2, 0x0, 0x4, 0xA1, 0xB2, 0xC3, 0xD4,
-        0x4, 0xD2, 0x0, 0x0, 0x0, 0x0
+            //This is the string "hmac-md5.sig-alg.reg.int" in octal, terminated in 00
+            0x8, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x6D, 0x64,
+            0x35, 0x7, 0x73, 0x69, 0x67, 0x2D, 0x61, 0x6C, 0x67,
+            0x3, 0x72, 0x65, 0x67, 0x3, 0x69, 0x6E, 0x74, 0x0,
+
+            //this is the time signed 123456789 == 0x75bcd15
+            0x0, 0x0, 0x7, 0x5B, 0xCD, 0x15,
+
+            // this the fudge 1234
+            0x4, 0xD2,
+
+            // this is the macsize = 4
+            0x0, 0x4,
+
+            // this is the mac = [0xA1, 0xB2, 0xC3, 0xD4]
+            0xA1, 0xB2, 0xC3, 0xD4,
+
+            // this is the original id = 1234
+            0x4, 0xD2,
+
+            // this is the error = 0
+            0x0, 0x0,
+
+            // this is the other len = 0
+            0x0, 0x0
+
+            // No other data, so its empty!
         ];
 
         for i in 0..bytes.len() {
@@ -593,14 +614,35 @@ mod tsig_rdata_test {
     }
 
     #[test]
-    #[ignore = "Fix test"]
     fn from_bytes_test(){
         let bytes = vec![
-        0x8, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x6D, 0x64,
-        0x35, 0x7, 0x73, 0x69, 0x67, 0x2D, 0x61, 0x6C, 0x67,
-        0x3, 0x72, 0x65, 0x67, 0x3, 0x69, 0x6E, 0x74, 0x0, 0x0, 0x0, 0x0,
-        0x0, 0x7, 0x5B, 0xCD, 0x15, 0x4, 0xD2, 0x0, 0x4, 0xA1, 0xB2, 0xC3, 0xD4,
-        0x4, 0xD2, 0x0, 0x0, 0x0, 0x0
+            //This is the string "hmac-md5.sig-alg.reg.int" in octal, terminated in 00
+            0x8, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x6D, 0x64,
+            0x35, 0x7, 0x73, 0x69, 0x67, 0x2D, 0x61, 0x6C, 0x67,
+            0x3, 0x72, 0x65, 0x67, 0x3, 0x69, 0x6E, 0x74, 0x0,
+
+            //this is the time signed 123456789 == 0x75bcd15
+            0x0, 0x0, 0x7, 0x5B, 0xCD, 0x15,
+
+            // this the fudge 1234
+            0x4, 0xD2,
+
+            // this is the macsize = 4
+            0x0, 0x4,
+
+            // this is the mac = [0xA1, 0xB2, 0xC3, 0xD4]
+            0xA1, 0xB2, 0xC3, 0xD4,
+
+            // this is the original id = 1234
+            0x4, 0xD2,
+
+            // this is the error = 0
+            0x0, 0x0,
+
+            // this is the other len = 0
+            0x0, 0x0
+
+            // No other data, so its empty!
         ];
 
         let tsig_rdata_result = TSigRdata::from_bytes(&bytes, &bytes);
diff --git a/src/message/resource_record.rs b/src/message/resource_record.rs
index 78017e58..eda68225 100644
--- a/src/message/resource_record.rs
+++ b/src/message/resource_record.rs
@@ -86,7 +86,7 @@ impl ResourceRecord {
                 rtype: Rrtype::A,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::A(val),
             },
             Rdata::NS(val) => ResourceRecord {
@@ -94,7 +94,7 @@ impl ResourceRecord {
                 rtype: Rrtype::NS,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::NS(val),
             },
             Rdata::CNAME(val) => ResourceRecord {
@@ -102,7 +102,7 @@ impl ResourceRecord {
                 rtype: Rrtype::CNAME,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::CNAME(val),
             },
             Rdata::SOA(val) => ResourceRecord {
@@ -110,7 +110,7 @@ impl ResourceRecord {
                 rtype: Rrtype::SOA,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::SOA(val),
             },
             Rdata::PTR(val) => ResourceRecord {
@@ -118,7 +118,7 @@ impl ResourceRecord {
                 rtype: Rrtype::PTR,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::PTR(val),
             },
             Rdata::HINFO(val) => ResourceRecord {
@@ -126,7 +126,7 @@ impl ResourceRecord {
                 rtype: Rrtype::HINFO,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::HINFO(val),
             },
             Rdata::MX(val) => ResourceRecord {
@@ -134,7 +134,7 @@ impl ResourceRecord {
                 rtype: Rrtype::MX,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::MX(val),
             },
             Rdata::TXT(val) => ResourceRecord {
@@ -142,7 +142,7 @@ impl ResourceRecord {
                 rtype: Rrtype::TXT,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::TXT(val),
             },
             Rdata::AAAA(val) => ResourceRecord {
@@ -150,7 +150,7 @@ impl ResourceRecord {
                 rtype: Rrtype::AAAA,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::AAAA(val),
             },
             Rdata::OPT(val) => ResourceRecord {
@@ -158,7 +158,7 @@ impl ResourceRecord {
                 rtype: Rrtype::OPT,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::OPT(val),
             },
             Rdata::DS(val) => ResourceRecord {
@@ -166,7 +166,7 @@ impl ResourceRecord {
                 rtype: Rrtype::DS,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::DS(val),
             },
             Rdata::RRSIG(val) => ResourceRecord {
@@ -174,7 +174,7 @@ impl ResourceRecord {
                 rtype: Rrtype::RRSIG,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::RRSIG(val),
             },
             Rdata::NSEC(val) => ResourceRecord {
@@ -182,7 +182,7 @@ impl ResourceRecord {
                 rtype: Rrtype::NSEC,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::NSEC(val),
             },
             Rdata::DNSKEY(val) => ResourceRecord {
@@ -190,7 +190,7 @@ impl ResourceRecord {
                 rtype: Rrtype::DNSKEY,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::DNSKEY(val),
             },
             Rdata::NSEC3(val) => ResourceRecord {
@@ -198,7 +198,7 @@ impl ResourceRecord {
                 rtype: Rrtype::NSEC3,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::NSEC3(val),
             },
             Rdata::NSEC3PARAM(val) => ResourceRecord {
@@ -206,15 +206,15 @@ impl ResourceRecord {
                 rtype: Rrtype::NSEC3PARAM,
                 rclass: Rclass::IN,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::NSEC3PARAM(val),
             },
             Rdata::TSIG(val) => ResourceRecord {
                 name: DomainName::new(),
                 rtype: Rrtype::TSIG,
-                rclass: Rclass::IN,
+                rclass: Rclass::ANY,
                 ttl: 0 as u32,
-                rdlength: 0 as u16,
+                rdlength: val.to_bytes().len() as u16,
                 rdata: Rdata::TSIG(val),
             },
             _ => ResourceRecord {
diff --git a/src/message/rrset.rs b/src/message/rrset.rs
new file mode 100644
index 00000000..00e5d0a9
--- /dev/null
+++ b/src/message/rrset.rs
@@ -0,0 +1,185 @@
+use crate::message::Rtype;
+use crate::message::Rclass;
+use crate::message::resource_record::ResourceRecord;
+use std::collections::HashSet;
+
+/// Represents a set of resource records (RRset).
+#[derive(Debug)]
+pub struct RRset {
+    /// The name of the domain associated with this RRset.
+    name: String,
+    /// The type of resource record in this RRset.
+    rtype: Rtype,
+    /// The class of resource record in this RRset.
+    rclass: Rclass,
+    /// The time to live (TTL) value for records in this RRset.
+    ttl: u32,
+    /// The set of resource records belonging to this RRset.
+    records: HashSet<ResourceRecord>,
+}
+
+impl RRset {
+    /// Creates a new RRset.
+    pub fn new(name: String, rtype: Rtype, rclass: Rclass, ttl: u32) -> RRset {
+        RRset {
+            name,
+            rtype,
+            rclass,
+            ttl,
+            records: HashSet::new(),
+        }
+    }
+
+    /// Adds a resource record to this RRset.
+    pub fn add_record(&mut self, record: ResourceRecord) {
+        self.records.insert(record);
+    }
+
+    /// Gets the name of the domain associated with this RRset.
+    pub fn get_name(&self) -> &String {
+        &self.name
+    }
+
+    /// Gets the type of resource record in this RRset.
+    pub fn get_type(&self) -> Rtype {
+        self.rtype
+    }
+
+    /// Gets the class of resource record in this RRset.
+    pub fn get_class(&self) -> Rclass {
+        self.rclass
+    }
+
+    /// Gets the time to live (TTL) value for records in this RRset.
+    pub fn get_ttl(&self) -> u32 {
+        self.ttl
+    }
+
+    /// Gets the set of resource records belonging to this RRset.
+    pub fn get_records(&self) -> &HashSet<ResourceRecord> {
+        &self.records
+    }
+
+    /// Gets the labels of the domain associated with this RRset.
+    pub fn get_labels(&self) -> usize {
+        self.name.split('.').count()
+    }
+
+    /// Serializes the RRset to a byte array for signing.
+    pub fn to_bytes(&self) -> Vec<u8> {
+        let mut bytes = Vec::new();
+        for record in &self.records {
+            bytes.extend(record.to_bytes());  // Assuming ResourceRecord has a to_bytes method
+        }
+        bytes
+    }
+}
+
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::message::Rtype;
+    use crate::message::Rclass;
+    use crate::message::resource_record::{ResourceRecord, Rdata, ARdata, NsRdata, CnameRdata};
+    use std::net::IpAddr;
+    use std::collections::HashSet;
+
+    #[test]
+    fn test_create_rrset() {
+        let name = "example.com".to_string();
+        let rtype = Rtype::A;
+        let rclass = Rclass::IN;
+        let ttl = 3600;
+
+        let rrset = RRset::new(name.clone(), rtype, rclass, ttl);
+
+        assert_eq!(rrset.get_name(), &name);
+        assert_eq!(rrset.get_type(), Rtype::A);
+        assert_eq!(rrset.get_class(), Rclass::IN);
+        assert_eq!(rrset.get_ttl(), 3600);
+        assert_eq!(rrset.get_labels(), 2);
+        assert!(rrset.get_records().is_empty());
+    }
+
+    #[test]
+    fn test_add_record() {
+        let name = "example.com".to_string();
+        let rtype = Rtype::A;
+        let rclass = Rclass::IN;
+        let ttl = 3600;
+
+        let mut rrset = RRset::new(name.clone(), rtype, rclass, ttl);
+
+        let mut a_rdata = Rdata::A(ARdata::new());
+        match a_rdata {
+            Rdata::A(ref mut val) => val.set_address(IpAddr::from([127, 0, 0, 1])),
+            _ => unreachable!(),
+        }
+
+        let record = ResourceRecord::new(a_rdata);
+        rrset.add_record(record);
+
+        assert_eq!(rrset.get_records().len(), 1);
+    }
+
+    #[test]
+    fn test_get_name() {
+        let name = "example.com".to_string();
+        let rtype = Rtype::A;
+        let rclass = Rclass::IN;
+        let ttl = 3600;
+
+        let rrset = RRset::new(name.clone(), rtype, rclass, ttl);
+
+        assert_eq!(rrset.get_name(), &name);
+    }
+
+    #[test]
+    fn test_get_type() {
+        let name = "example.com".to_string();
+        let rtype = Rtype::NS;
+        let rclass = Rclass::IN;
+        let ttl = 3600;
+
+        let rrset = RRset::new(name.clone(), rtype, rclass, ttl);
+
+        assert_eq!(rrset.get_type(), Rtype::NS);
+    }
+
+    #[test]
+    fn test_get_class() {
+        let name = "example.com".to_string();
+        let rtype = Rtype::MX;
+        let rclass = Rclass::CH;
+        let ttl = 3600;
+
+        let rrset = RRset::new(name.clone(), rtype, rclass, ttl);
+
+        assert_eq!(rrset.get_class(), Rclass::CH);
+    }
+
+    #[test]
+    fn test_get_ttl() {
+        let name = "example.com".to_string();
+        let rtype = Rtype::A;
+        let rclass = Rclass::IN;
+        let ttl = 7200;
+
+        let rrset = RRset::new(name.clone(), rtype, rclass, ttl);
+
+        assert_eq!(rrset.get_ttl(), 7200);
+    }
+
+    #[test]
+    fn test_get_labels() {
+        let name = "sub.example.com".to_string();
+        let rtype = Rtype::A;
+        let rclass = Rclass::IN;
+        let ttl = 3600;
+
+        let rrset = RRset::new(name.clone(), rtype, rclass, ttl);
+
+        assert_eq!(rrset.get_labels(), 3);
+    }
+}
diff --git a/src/resolver_cache.rs b/src/resolver_cache.rs
index fce779d1..8bbd8fc4 100644
--- a/src/resolver_cache.rs
+++ b/src/resolver_cache.rs
@@ -179,7 +179,7 @@ impl ResolverCache {
         qtype: Rrtype,
         qclass: Rclass,
     ) -> Option<Vec<ResourceRecord>> {
-        let rr_stored_data = self.cache_answer.get(domain_name, qtype, qclass);
+        let rr_stored_data = self.cache_answer.get(domain_name, Some(qtype), qclass);
 
         if let Some(rr_stored_data) = rr_stored_data {
             let mut rr_vec = Vec::new();
@@ -199,7 +199,7 @@ impl ResolverCache {
         qtype: Rrtype,
         qclass: Rclass,
     ) -> Option<Vec<ResourceRecord>> {
-        let rr_stored_data = self.cache_authority.get(domain_name, qtype, qclass);
+        let rr_stored_data = self.cache_authority.get(domain_name, Some(qtype), qclass);
 
         if let Some(rr_stored_data) = rr_stored_data {
             let mut rr_vec = Vec::new();
@@ -219,7 +219,7 @@ impl ResolverCache {
         qtype: Rrtype,
         qclass: Rclass,
     ) -> Option<Vec<ResourceRecord>> {
-        let rr_stored_data = self.cache_additional.get(domain_name, qtype, qclass);
+        let rr_stored_data = self.cache_additional.get(domain_name, Some(qtype), qclass);
 
         if let Some(rr_stored_data) = rr_stored_data {
             let mut rr_vec = Vec::new();
@@ -238,7 +238,7 @@ impl ResolverCache {
         qtype: Rrtype,
         qclass: Rclass,
     ) -> Option<Rcode> {
-        let rr_stored_data = self.cache_answer.get(domain_name, qtype, qclass);
+        let rr_stored_data = self.cache_answer.get(domain_name, Some(qtype), qclass);
 
         if let Some(rr_stored_data) = rr_stored_data {
             Some(rr_stored_data[0].get_rcode())
@@ -515,7 +515,7 @@ mod resolver_cache_test {
 
         let rr = resolver_cache
             .cache_answer
-            .get(domain_name.clone(), Rrtype::A, Rclass::IN)
+            .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN)
             .unwrap();
 
         assert_eq!(rr[0].get_resource_record(), resource_record);
@@ -547,7 +547,7 @@ mod resolver_cache_test {
 
         let rr = resolver_cache
             .cache_authority
-            .get(domain_name.clone(), Rrtype::A, Rclass::IN)
+            .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN)
             .unwrap();
 
         assert_eq!(rr[0].get_resource_record(), resource_record);
@@ -579,7 +579,7 @@ mod resolver_cache_test {
 
         let rr = resolver_cache
             .cache_additional
-            .get(domain_name.clone(), Rrtype::A, Rclass::IN)
+            .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN)
             .unwrap();
 
         assert_eq!(rr[0].get_resource_record(), resource_record);
@@ -647,15 +647,15 @@ mod resolver_cache_test {
 
         let rr_answer = resolver_cache
             .cache_answer
-            .get(domain_name.clone(), Rrtype::A, Rclass::IN)
+            .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN)
             .unwrap();
         let rr_authority = resolver_cache
             .cache_authority
-            .get(domain_name.clone(), Rrtype::A, Rclass::IN)
+            .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN)
             .unwrap();
         let rr_additional = resolver_cache
             .cache_additional
-            .get(domain_name.clone(), Rrtype::A, Rclass::IN)
+            .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN)
             .unwrap();
 
         assert_eq!(rr_answer[0].get_resource_record(), resource_record_1);
@@ -1320,15 +1320,15 @@ mod resolver_cache_test {
 
         let rr_answer = resolver_cache
             .cache_answer
-            .get(domain_name.clone(), Rrtype::A, Rclass::IN);
+            .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
         let rr_authority =
             resolver_cache
                 .cache_authority
-                .get(domain_name.clone(), Rrtype::A, Rclass::IN);
+                .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
         let rr_additional =
             resolver_cache
                 .cache_additional
-                .get(domain_name.clone(), Rrtype::A, Rclass::IN);
+                .get(domain_name.clone(), Some(Rrtype::A), Rclass::IN);
 
         assert_eq!(rr_answer, None);
         assert_eq!(rr_authority, None);
diff --git a/src/tsig.rs b/src/tsig.rs
new file mode 100644
index 00000000..93b9007a
--- /dev/null
+++ b/src/tsig.rs
@@ -0,0 +1,628 @@
+pub mod tsig_algorithm;
+
+use crypto::mac::MacResult;
+use crate::domain_name::DomainName;
+use std::time::SystemTime;
+use crate::message::rclass::Rclass;
+use crate::message::resource_record::{ResourceRecord, ToBytes};
+
+use crate::message::{rdata::tsig_rdata::TSigRdata, DnsMessage,};
+use crate::message::rdata::Rdata;
+use crypto::hmac::Hmac as crypto_hmac;
+use crypto::mac::Mac as crypto_mac;
+use crypto::{sha1::Sha1,sha2::Sha256};
+use tsig_algorithm::TsigAlgorithm;
+use crate::message::rcode::Rcode;
+
+
+//TODO: Encontrar alguna manera de pasar una referencia Digest u Hmac de un algoritmo no especificado
+// función auxiliar para evitar la redundancia de código en sign_tsig
+fn set_tsig_rd(name: String, original_id: u16, result: MacResult,
+               fudge: u16, time_signed: u64, mac_size: u16) -> TSigRdata{
+    let mut tsig_rd: TSigRdata = TSigRdata::new();
+    let mac = result.code();
+
+    //Convertir los bytes brutos a una cadena hexadecimal
+    let a_name = name.to_lowercase();
+    let a_name = DomainName::new_from_string(a_name);
+    //añadir los valores correspondientes al tsig_rd
+    tsig_rd.set_algorithm_name(a_name);
+    tsig_rd.set_mac_size(mac_size);
+    tsig_rd.set_mac(mac.to_vec());
+    tsig_rd.set_fudge(fudge);
+    tsig_rd.set_original_id(original_id);
+    tsig_rd.set_time_signed(time_signed);
+
+    return tsig_rd;
+}
+//TODO: crear una función para simplificar la extracción de bits paa simplificar código
+// This function extracts the digest 
+#[doc = r"This function recives a DNS message and generate the digest da. Requested by RFC 8945 4.3.3 "]
+pub fn get_digest_request(mac: Vec<u8> ,dns_msg: Vec<u8>, tsig_rr: ResourceRecord) -> Vec<u8> {
+    let mut res: Vec<u8> = vec![];
+
+    if mac.len() != 0 {
+        let mac_len = mac.len() as u16;
+        let bytes_mac_len = mac_len.to_be_bytes();
+        res.push(bytes_mac_len[0]);
+        res.push(bytes_mac_len[1]);
+        res.extend(mac.clone());
+    }
+    res.extend(dns_msg.clone());
+    let tsig_rdata = tsig_rr.get_rdata();
+    res.extend(tsig_rr.get_name().to_bytes());
+    //The below shifts are meant to correctly retreive theby
+    //processing TSIG RR
+    let rclass_bytes: u16 = Rclass::from(tsig_rr.get_rclass()).into();
+    let rclass_ubyte = (rclass_bytes >> 8) as u8;
+    let rclass_lbyte = rclass_bytes as u8;
+    res.push(rclass_ubyte);
+    res.push(rclass_lbyte);
+
+    let rclass_ttl:  u32 = tsig_rr.get_ttl();
+    let r_ttl1 = (rclass_ttl >> 24) as u8;
+    let r_ttl2 = (rclass_ttl >> 16) as u8;
+    let r_ttl3 = (rclass_ttl >>  8) as u8;
+    let r_ttl4 = rclass_ttl as u8;
+    res.push(r_ttl1);
+    res.push(r_ttl2);
+    res.push(r_ttl3);
+    res.push(r_ttl4);
+
+    //processing TSIG RDATA
+    let tsig_rd = match tsig_rdata {
+        Rdata::TSIG(tsig_rd) => tsig_rd,
+        _ => panic!()
+    };
+    let a_name = tsig_rd.get_algorithm_name().to_bytes();
+    // Remember that time_signed is u48
+    let tsig_rd_time_signed: u64 = tsig_rd.get_time_signed();
+    let tsig_rd_fudge: u16 = tsig_rd.get_fudge();
+    let tsig_rd_error: u16= tsig_rd.get_error();
+    let tsig_rd_other_len: u16 =  tsig_rd.get_other_len();
+    let tsig_rd_other_data = tsig_rd.get_other_data();
+
+    res.extend(a_name);
+
+    let time_s1 = (tsig_rd_time_signed >> 40) as u8;
+    let time_s2 = (tsig_rd_time_signed >> 32) as u8;
+    let time_s3 = (tsig_rd_time_signed >> 24) as u8;
+    let time_s4 = (tsig_rd_time_signed >> 16) as u8;
+    let time_s5 = (tsig_rd_time_signed >> 8) as u8;
+    let time_s6 = (tsig_rd_time_signed) as u8;
+    res.push(time_s1);
+    res.push(time_s2);
+    res.push(time_s3);
+    res.push(time_s4);
+    res.push(time_s5);
+    res.push(time_s6);
+
+    let fudge1 = (tsig_rd_fudge >> 8) as u8;
+    let fudge2 = (tsig_rd_fudge) as u8;
+    res.push(fudge1);
+    res.push(fudge2);
+
+    let error1 = (tsig_rd_error >> 8) as u8;
+    let error2 = (tsig_rd_error) as u8;
+    res.push(error1);
+    res.push(error2);
+
+    let otherl1 = (tsig_rd_other_len >> 8) as u8;
+    let otherl2 = (tsig_rd_other_len) as u8;
+    res.push(otherl1);
+    res.push(otherl2);
+
+    res.extend(tsig_rd_other_data);
+
+    return res;
+}
+
+fn digest(bytes: Vec<u8>, tsig_algorithm: TsigAlgorithm, key: Vec<u8>) -> Vec<u8>{
+    match tsig_algorithm {
+        TsigAlgorithm::HmacSha1 => {
+
+            //new_query_message.push();
+            let mut hasher = crypto_hmac::new(Sha1::new(), &key);
+            hasher.input(&bytes[..]);
+            hasher.result().code().to_vec()
+        },
+        TsigAlgorithm::HmacSha256 => {
+            let mut hasher = crypto_hmac::new(Sha256::new(), &key);
+            hasher.input(&bytes[..]);
+            hasher.result().code().to_vec()
+        }
+        TsigAlgorithm::UNKNOWN(a) => {
+            panic!("Unknown algorithm {}", a);
+        }
+    }
+}
+
+//RFC 8945, section 5.1
+#[doc = r"This function creates the signature of a DnsMessage with  a  key in bytes and the algName that will be used to encrypt the key."]
+pub fn sign_tsig(query_msg: &mut DnsMessage, key: &[u8], alg_name: TsigAlgorithm,
+                 fudge: u16, time_signed: u64, key_name: String, mac_request: Vec<u8>) {
+    let tsig_rd: TSigRdata;
+    let new_query_message = query_msg.clone();
+    let original_id = query_msg.get_query_id();
+    let alg_name_str = String::from(alg_name.clone());
+    let tsig_rr= set_tsig_vars(alg_name_str.as_str(), key_name.as_str(),
+                               time_signed, fudge);
+    let digest_comp = get_digest_request(mac_request, new_query_message.to_bytes(),
+                                         tsig_rr);
+    match alg_name {
+        
+        TsigAlgorithm::HmacSha1 => {
+
+            //new_query_message.push();
+            let mut hasher = crypto_hmac::new(Sha1::new(), key);
+            hasher.input(&digest_comp[..]);
+            let result = hasher.result();
+            tsig_rd = set_tsig_rd( 
+                "hmac-sha1".to_lowercase(), 
+                original_id,
+                result,
+                fudge, 
+                time_signed,
+                 20);
+            
+        },
+        TsigAlgorithm::HmacSha256 => {
+            let mut hasher = crypto_hmac::new(Sha256::new(), key);
+            hasher.input(&digest_comp[..]);
+            let result = hasher.result();
+            tsig_rd = set_tsig_rd( 
+                "hmac-sha256".to_lowercase(),
+                original_id,
+                result,
+                fudge, 
+                time_signed,
+                32);
+            
+        },
+        TsigAlgorithm::UNKNOWN(a) => {
+            panic!("Unknown algorithm {}", a);
+        }
+    }
+    let rr_len = tsig_rd.to_bytes().len() as u16;
+    let mut new_rr: ResourceRecord = ResourceRecord::new(Rdata::TSIG(tsig_rd));
+    new_rr.set_name(DomainName::new_from_string(key_name));
+    new_rr.set_rdlength(rr_len);
+    let mut vec: Vec<ResourceRecord> = vec![];
+    vec.push(new_rr);
+    query_msg.add_additionals(vec);
+}
+
+//Revisa si el nombre de la llave es correcto
+fn check_key(key_in_rr:String, key_name:String)-> bool {
+    key_in_rr.eq(&key_name)
+}
+
+//Verifica que el algoritmo esté disponible, y además esté implementado
+fn check_alg_name(alg_name:&String, alg_list: Vec<(String,bool)>) -> bool{
+    let mut answer: bool = false;
+    for (name,available) in alg_list {
+        if name.eq(alg_name){
+            if available {
+                answer = true;
+            }
+        }
+    }
+    return answer
+}
+
+//Verifica que los mac sean iguales
+fn check_mac(new_mac: Vec<u8>, mac: Vec<u8>) -> bool{
+    if mac.len()!=new_mac.len(){
+        return false
+    }
+    for i in 0..mac.len(){
+        if new_mac[i]!=mac[i]{
+            return false
+        }
+    }
+    true
+}
+
+//Verifica el error de la sección 5.2.3 
+fn check_time_values(mytime: u64,fudge: u16, time: u64) -> bool {
+    let part1 = (time - (fudge as u64)) < mytime;
+    let part2 = mytime < (time+(fudge as u64));
+    part1 && part2
+}
+
+//RFC 8945 5.2 y 5.4
+//verificar que existen los resource records que corresponden a tsig
+//vector con resource records que son TSIG. Luego se Verifica si hay algún tsig rr
+fn check_exists_tsig_rr(add_rec: &Vec<ResourceRecord>) -> bool {
+    let filtered_tsig:Vec<_> = add_rec.iter()
+                                .filter(|tsig| 
+                                if let Rdata::TSIG(_) = tsig.get_rdata() {true}
+                                else {false}).collect();
+
+    filtered_tsig.len()==0
+}
+
+
+//Debe haber un único tsig
+//Tsig RR debe ser el último en la sección adicional, y debe ser único2
+fn check_last_one_is_tsig(add_rec: &Vec<ResourceRecord>) -> bool {
+    let filtered_tsig:Vec<_> = add_rec.iter()
+                                .filter(|tsig| 
+                                if let Rdata::TSIG(_) = tsig.get_rdata() {true}
+                                else {false}).collect();
+    
+    let islast = if let Rdata::TSIG(_) = add_rec[add_rec.len()-1].get_rdata() {false} else {true};
+
+    filtered_tsig.len()>1 || islast
+}
+
+#[doc = r"This function process a tsig message, checking for errors in the DNS message"]
+pub fn process_tsig(msg: &DnsMessage, key:&[u8], key_name: String, time: u64,
+                    available_algorithm: Vec<(String, bool)>, mac_to_process: Vec<u8>) -> (bool, Rcode) {
+    let mut retmsg = msg.clone();
+    let mut addit = retmsg.get_additional();
+    //RFC 8945 5.2 y 5.4
+    //verificar que existen los resource records que corresponden a tsig
+    //vector con resource records que son TSIG. Luego se Verifica si hay algún tsig rr
+    if check_exists_tsig_rr(&addit) {
+        println!("RCODE 1: FORMERR");
+        return (false, Rcode::FORMERR);
+    }
+    
+    //Debe haber un único tsig
+    //Tsig RR debe ser el último en la sección adicional, y debe ser único
+    if check_last_one_is_tsig(&addit) {
+        println!("RCODE 1: FORMERR");
+        return (false, Rcode::FORMERR);
+    }
+
+    //sacar el último elemento del vector resource record, y disminuir elvalor de ARCOUNT
+    let rr_copy = addit.pop().expect("No tsig rr");
+    let tsig_rr_copy: TSigRdata;
+    match rr_copy.get_rdata() {
+        Rdata::TSIG(data) =>{
+            tsig_rr_copy = data;
+        }
+        _ => {
+            println!("error");
+            unimplemented!("TODO: error code if last rr is not tsig; FORMERR")
+        }
+    }
+
+    //RFC 8945 5.2.1
+    let key_in_rr = rr_copy.get_name().get_name();
+    let name_alg = tsig_rr_copy.get_algorithm_name().get_name();
+
+    let flag = check_alg_name(&name_alg, available_algorithm);
+    if !flag {
+        println!("RCODE 9: NOAUTH\n TSIG ERROR 17: BADKEY");
+        return (false, Rcode::BADKEY);
+    }
+
+    let cond1 = check_key(key_in_rr.clone(), key_name.clone());
+    if !cond1 {
+        println!("RCODE 9: NOAUTH\n TSIG ERROR 17: BADKEY");
+        println!("key in rr: {:?} key given {:?}", key_in_rr, key_name);
+        return (false, Rcode::BADKEY);
+    }
+
+    //RFC 8945 5.2.2
+    //retmsg.set_additional(addit);
+    let fudge = tsig_rr_copy.get_fudge();
+    let time_signed = tsig_rr_copy.get_time_signed();
+    let mac_received = tsig_rr_copy.get_mac();
+    let mut new_alg_name: TsigAlgorithm = TsigAlgorithm::HmacSha1;
+    match name_alg.as_str() {
+        "hmac-sha1" => new_alg_name = TsigAlgorithm::HmacSha1,
+        "hmac-sha256" => new_alg_name = TsigAlgorithm::HmacSha256,
+        &_ => println!("Not supported algorithm")
+    }
+
+    //let nuevo_len_arcount = addit.len() as u16;
+    //let mut new_header = retmsg.get_header();
+    //new_header.set_arcount(nuevo_len_arcount);
+    //retmsg.set_header(new_header);
+    retmsg.set_additional(addit);
+    retmsg.update_header_counters();
+
+    // This gets the bytes to use the function and generate the digest
+    let bytes_to_hash = get_digest_request(mac_to_process, retmsg.to_bytes(), rr_copy);
+
+    let new_mac = digest(bytes_to_hash, new_alg_name, key.to_vec());
+
+    let cond2 = check_mac(new_mac, mac_received);
+
+    if !cond2 {
+        println!("RCODE 9: NOAUTH\n TSIG ERROR 16: BADSIG");
+        return (false, Rcode::BADSIG)
+    }
+    //let mytime = SystemTime::now().duration_since(UNIX_EPOCH).expect("no debería fallar el tiempo");
+    let cond3 = check_time_values(time, fudge, time_signed);
+    if !cond3 {
+        println!("RCODE 9: NOAUTH\n TSIG ERROR 18: BADTIME");
+        return (false, Rcode::BADTIME)
+    }
+    (true, Rcode::NOERROR)
+
+}
+
+pub fn immediate_process_tsig(msg: &DnsMessage, key:&[u8], key_name: String,
+    available_algorithm: Vec<(String, bool)>, mac_to_process: Vec<u8>) -> (bool, Rcode) {
+    
+    let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+    process_tsig(msg, key, key_name, time, available_algorithm, mac_to_process)
+}
+
+//Auxiliar function to create the TSIG variables and resource recrods
+#[doc= r"This function helps to set create a partial TSIG resource record on  a DNS query"]
+fn set_tsig_vars(alg_name: &str, name: &str, time_signed: u64, fudge: u16) -> ResourceRecord{
+    //TSIG Variables
+    // TSIG RDATA
+    let mut tsig_rd: TSigRdata = TSigRdata::new();
+    tsig_rd.set_algorithm_name(DomainName::new_from_str(alg_name));
+    tsig_rd.set_time_signed(time_signed);
+    tsig_rd.set_fudge(fudge);
+    tsig_rd.set_error(0);
+    tsig_rd.set_other_len(0);
+    // TSIG RR
+    let mut tsig_rr = ResourceRecord::new(Rdata::TSIG(tsig_rd));
+    tsig_rr.set_name(DomainName::new_from_str(name));
+    //tsig_rr.set_rclass(Rclass::ANY);
+    tsig_rr.set_ttl(0);
+
+    return tsig_rr
+}                                                 
+
+//Sección de tests unitarios
+
+#[cfg(test)]
+mod tsig_test {
+    use super::*;
+    use crate::message::rdata::a_rdata::ARdata;
+    use crate::message::rrtype::Rrtype;
+
+    #[test]
+    fn check_process_tsig_exists() {
+        //Server process
+        let response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        //Client process
+        let key_name:String = "".to_string();
+        let mut lista :Vec<(String, bool)>  = vec![];
+        let server_key = b"1234567890";
+        lista.push((String::from("hmac-sha256"),true));
+        let (answer, error) = process_tsig(& response, server_key, key_name, 21010, lista, vec![]);
+        assert!(!answer);
+        assert_eq!(error,Rcode::FORMERR);
+    }
+
+    #[test]
+    fn check_process_tsig_exists2() {
+        //Server process
+        let mut response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        let server_key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha256;
+        let alg_name2 = TsigAlgorithm::HmacSha256;
+        let fudge = 300;
+        let time_signed = 21000;
+        let key_name = "".to_string();
+
+        sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name.clone(), vec![]);
+        let mut response_capture = response.clone();
+        sign_tsig(&mut response_capture, server_key, alg_name2, fudge, time_signed, key_name.clone(), vec![]);
+        //Client process
+        let key_name:String = "".to_string();
+        let mut lista :Vec<(String, bool)>  = vec![];
+        lista.push((String::from("hmac-sha256"),true));
+        let (control_answer, _) = process_tsig(& response, server_key, key_name.clone(),21010, lista.clone(), vec![]);
+        assert!(control_answer);
+        let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]);
+        assert!(!answer);
+        assert_eq!(error, Rcode::FORMERR);
+    }
+
+    // verificar que no se haya añadido otro resource record en el additionals luego de añadir un tsig_rr
+    #[test]
+    fn check_process_tsig_exists3(){
+        //Server process
+        let mut response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        let server_key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha256;
+        let fudge = 300;
+        let time_signed = 21000;
+        let key_name = "";
+        //se crea un rr TSIG que se añadirá en adittionals
+        sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name.to_string(), vec![]);
+
+        //se agrega otro resource record en el additional...
+        let mut new_additional = Vec::<ResourceRecord>::new();
+        let a_rdata5 = Rdata::A(ARdata::new());
+        let rr5 = ResourceRecord::new(a_rdata5);
+        new_additional.push(rr5);
+        response.add_additionals(new_additional);
+        let response_capture = response.clone();
+
+        //Client process
+        let key_name:String = "".to_string();
+        let mut lista :Vec<(String, bool)>  = vec![];
+        lista.push((String::from("hmac-sha256"),true));
+        let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]);
+        assert!(!answer);
+        assert_eq!(error, Rcode::FORMERR);
+    }
+    #[test]
+    fn check_process_tsig_alg_name() {
+        //Server process
+        let mut response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        let server_key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha256;
+        let fudge = 300;
+        let time_signed = 21000;
+        let key_name = "".to_string();
+        sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]);
+        let response_capture = response.clone();
+        //Client process
+        let key_name:String = "".to_string();
+        let mut lista :Vec<(String, bool)>  = vec![];
+        //suponemos que hmacsha256 no está disponible
+        lista.push((String::from("hmac-sha1"),true));
+        let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]);
+        assert!(!answer);
+        assert_eq!(error,Rcode::BADKEY);
+    }
+    #[test]
+    fn check_process_tsig_alg_name2() {
+        //Server process
+        let mut response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        let server_key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha256;
+        let fudge = 300;
+        let time_signed = 21000;
+        let key_name = "".to_string();
+        sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]);
+        let response_capture = response.clone();
+        //Client process
+        let key_name:String = "".to_string();
+        let mut lista :Vec<(String, bool)>  = vec![];
+        //suponemos que reconocemos hmac-sha256, pero no está implementado
+        lista.push((String::from("hmac-sha256"),false));
+        let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]);
+        assert!(!answer);
+        assert_eq!(error,Rcode::BADKEY);
+    }
+    #[test]
+    fn check_process_tsig_key(){
+        //Server process
+        let mut response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        let server_key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha256;
+        let fudge = 300;
+        let time_signed = 21000;
+        let key_name = "".to_string();
+        sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]);
+        let response_capture = response.clone();
+        //Client process
+        let key_name:String = "different".to_string();
+        let mut lista :Vec<(String, bool)>  = vec![];
+        //suponemos que reconocemos hmac-sha256, pero no está implementado
+        lista.push((String::from("hmac-sha256"),false));
+        let (answer, error) = process_tsig(& response_capture, server_key, key_name, 21010, lista, vec![]);
+        assert!(!answer);
+        assert_eq!(error,Rcode::BADKEY);
+    }
+    //TODO: completar este test, hay cosas que faltan por implementar
+    #[test]
+    fn check_process_tsig_badsign(){
+        // Se establece un DnsMessage de prueba. Lo firmaremos, alteraremos la firma generada y esperamos recibir un error BADSIGN
+        let mut msg1 = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        let key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha1;
+        let fudge = 1000;
+        let time_signed = 210000000;
+        let key_name = "".to_string();
+        // se firma el mensaje con algoritmo SHA-1
+        sign_tsig(& mut msg1, key, alg_name, fudge, time_signed, key_name, vec![]);
+        let mut lista :Vec<(String, bool)>  = vec![];
+        lista.push((String::from("hmac-sha1"),true));
+        lista.push((String::from("hmac-sha256"),true));
+        // se verifica que el mensaje está firmado, pero se usa otra key
+        let key_name = "".to_string();
+        let key2 = b"12345678909";
+        let (_, error) = process_tsig(&mut msg1, key2, key_name, time_signed,lista, vec![]);
+        assert_eq!(error,Rcode::BADSIG);
+    }
+    #[test]
+    fn check_proces_tsig_badtime(){
+        //Server process
+        let mut response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        let server_key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha256;
+        let fudge = 300;
+        let time_signed = 21000;
+        let key_name = "".to_string();
+        sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]);
+        let response_capture = response.clone();
+        //Client process
+        let key_name:String = "".to_string();
+        let mut lista :Vec<(String, bool)>  = vec![];
+        //suponemos que reconocemos hmac-sha256, pero no está implementado
+        lista.push((String::from("hmac-sha256"),true));
+        let (answer, error) = process_tsig(& response_capture, server_key, key_name,
+                                        22010, lista, vec![]);
+        assert!(!answer);
+        assert_eq!(error,Rcode::BADTIME);
+    }
+    #[test]
+    fn check_process_tsig() {
+        //sender process
+        let mut response = DnsMessage::new_response_message(String::from("test.com"), "NS", "IN", 1, true, 1);
+        let server_key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha256;
+        let fudge = 300;
+        let time_signed = 21000;
+        let key_name = "".to_string();
+        sign_tsig(&mut response, server_key, alg_name, fudge, time_signed, key_name, vec![]);
+        let response_capture = response.clone();
+        //recv process
+        let key_name:String = "".to_string();
+        let mut lista :Vec<(String, bool)>  = vec![];
+        lista.push((String::from("hmac-sha256"),true));
+        let (answer, error) = process_tsig(& response_capture, server_key, key_name,
+                                        21010, lista, vec![]);
+        assert!(answer);
+        assert_eq!(error,Rcode::NOERROR);
+    }
+    //Unitary test to verify that the signer function is working properly
+    #[test]
+    fn check_signed_tsig() {
+        let key = b"1234567890";
+        let alg_name = TsigAlgorithm::HmacSha1;
+        let fudge = 0;
+        let time_signed = 0;
+        let id = 6502; 
+        let name: String = "".to_string();
+        let domain = DomainName::new_from_str("uchile.cl");
+        //DNS message
+        let mut q = DnsMessage::new_query_message(
+            domain.clone(),
+            Rrtype::A,
+            Rclass::ANY,
+            0, 
+            false,
+            id
+        );
+        //partial TSIG Resource record verify the signing process
+        let tsig_rr = set_tsig_vars(String::from(alg_name.clone()).as_str(), &name, time_signed, fudge);
+        let q_for_mac = q.clone();
+        //creation of the signature to compare
+        sign_tsig(&mut q, key, alg_name, fudge, time_signed, name, vec![]);
+        let firma_a_comparar = q.get_mac();
+        // creation of the signature digest
+        let dig_for_mac = get_digest_request(vec![],q_for_mac.to_bytes(), tsig_rr);
+        let mut hasher = crypto_hmac::new(Sha1::new(), key);
+        hasher.input(&dig_for_mac[..]);
+        
+        let result = hasher.result();
+        let mac_to_cmp = result.code();
+
+        let rr = q.get_additional().pop().expect("Should be a tsig");
+        match rr.get_rdata() {
+            Rdata::TSIG(data) => {
+                assert_eq!(data.get_algorithm_name(), DomainName::new_from_str("hmac-sha1"));
+                assert_eq!(data.get_time_signed(), time_signed);
+                assert_eq!(data.get_fudge() , fudge);
+                assert_eq!(data.get_mac_size(), 20);
+                assert_eq!(data.get_original_id(), id);
+                assert_eq!(data.get_error(), 0);
+                assert_eq!(data.get_other_len(), 0);
+                assert!(data.get_other_data().is_empty());
+            },
+            _ =>{
+                assert!(false);
+            }
+        }
+        println!("Comparando el mac");
+        for i in 0..mac_to_cmp.len() {
+            assert_eq!(mac_to_cmp[i], firma_a_comparar[i]);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tsig/tsig_algorithm.rs b/src/tsig/tsig_algorithm.rs
new file mode 100644
index 00000000..8701bd03
--- /dev/null
+++ b/src/tsig/tsig_algorithm.rs
@@ -0,0 +1,27 @@
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum TsigAlgorithm {
+    HmacSha1,
+    HmacSha256,
+    UNKNOWN(String),
+}
+
+impl From<TsigAlgorithm> for String {
+    fn from(alg: TsigAlgorithm) -> String {
+        match alg {
+            TsigAlgorithm::HmacSha1 => "hmac-sha1".to_string(),
+            TsigAlgorithm::HmacSha256 => "hmac-sha256".to_string(),
+            TsigAlgorithm::UNKNOWN(s) => s,
+        }
+    }
+}
+
+impl From<String> for TsigAlgorithm {
+    fn from(name: String) -> TsigAlgorithm {
+        match name {
+            name if name == "hmac-sha1" => TsigAlgorithm::HmacSha1,
+            name if name == "hmac-sha256" => TsigAlgorithm::HmacSha256,
+            _ => TsigAlgorithm::UNKNOWN(name),
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/integration_test.rs b/tests/integration_test.rs
index 1541b83c..3c6f72c3 100644
--- a/tests/integration_test.rs
+++ b/tests/integration_test.rs
@@ -1,8 +1,10 @@
+
 use std::{net::IpAddr, str::FromStr};
 use dns_rust::{async_resolver::{config::ResolverConfig, AsyncResolver}, client::client_error::ClientError, domain_name::DomainName, message::{rclass::Rclass, rdata::Rdata, resource_record::{ResourceRecord, ToBytes}, rrtype::Rrtype, DnsMessage}};
 
 
 
+
 // TODO: Change params type to intoDomainName
 async fn query_response(domain_name: &str, protocol: &str, qtype: &str) -> Result<Vec<ResourceRecord>, ClientError> {
 
@@ -13,6 +15,7 @@ async fn query_response(domain_name: &str, protocol: &str, qtype: &str) -> Resul
         domain_name,
         protocol,
         qtype,
+
         "IN").await;
 
     response.map(|lookup_response| lookup_response.to_vec_of_rr())
@@ -109,5 +112,3 @@ async fn no_resource_available() {
     assert!(response.is_err());
 }
 
-
-
diff --git a/tests/tsig_integration_tests.rs b/tests/tsig_integration_tests.rs
new file mode 100644
index 00000000..6d656f58
--- /dev/null
+++ b/tests/tsig_integration_tests.rs
@@ -0,0 +1,181 @@
+use std::{collections::HashMap, net:: UdpSocket, thread, time::Duration};
+use dns_rust::{domain_name::DomainName, message::{rdata::{tsig_rdata::TSigRdata, Rdata}, rrtype::Rrtype, DnsMessage},tsig::{process_tsig, sign_tsig}};
+use dns_rust::tsig::tsig_algorithm::TsigAlgorithm;
+use dns_rust::message::rcode::Rcode;
+use dns_rust::message::rclass::Rclass;
+
+
+///RFC 8945 TSIG tests
+/*This tests verifies section 5.3:
+   When a server has generated a response to a signed request, it signs
+   the response using the same algorithm and key.  The server MUST NOT
+   generate a signed response to a request if either the key is invalid
+   (e.g., key name or algorithm name are unknown) or the MAC fails
+   validation; see Section 5.3.2 for details of responding in these
+   cases.
+
+   It also MUST NOT generate a signed response to an unsigned request,
+   except in the case of a response to a client's unsigned TKEY request
+   if the secret key is established on the server side after the server
+   processed the client's request.  Signing responses to unsigned TKEY
+   requests MUST be explicitly specified in the description of an
+   individual secret key establishment algorithm [RFC3645].
+
+   The digest components used to generate a TSIG on a response are:
+
+      Request MAC
+      DNS Message (response)
+      TSIG Variables (response) 
+      
+    DISCLAIMER: Como no hay un "NameServer" implementado, se probó la firma y verififcaciónde TSIG utilizando 
+    threads y scokets. La idea central es tener un thread recibiendo datos de localhost, el cual tiene en alguna 
+    parte guardados pares (key, name) que serían utilizados para la autenticación (en este caso, se guardaron los 
+    pares en un hash_map. Como se guarden no es relevante para tsig, depende de la implementación del servidor. 
+    Lo único importante es que podamos buscar la llave asociada a un cierto nombre, de acuerdo a la solicitud que 
+    recibamos).
+    En este test se verifica a nivel macro el correcto flujo  de TSIG: primero se envia a un host en localhost 
+    una query firmada, el cual verifica la integridad de la query y responde con un respuesta firmada que será verificada.
+*/
+#[tokio::test]
+async fn tsig_signature() {
+    // the key to test tsig flow. The server should had the same key
+    let key = b"1234567890";
+    // global test variables
+    let alg_name = TsigAlgorithm::HmacSha1;
+    let fudge = 100;
+    let time_signed = 12345678;
+    let id = 6502; 
+    let name = "nictest.cl";
+    let mut dns_query_message =
+            DnsMessage::new_query_message(
+                DomainName::new_from_string(name.to_string()),
+                Rrtype::A,
+                Rclass::IN,
+                0,
+                false,
+                id);
+    //lista de algoritmos disponibles. En este caso, ambos host tendrán la misma
+    let mut a_algs :Vec<(String, bool)>  = vec![];
+    a_algs.push((String::from("hmac-sha1"),true));
+    a_algs.push((String::from("hmac-sha256"),true));
+    
+    
+    //Código para el servidor. Recibe un mensaje firmado, lo verifica y envía una repuesta autenticada, según lo descrito en el
+    //RFC 8945. Este servidor tiene su propia lista de algoritmos disponibles y llaves asociadas a nombres de dominio
+    fn host(){
+        println!("I am a host");
+        //la lista de algoritmos del host
+        let mut list :Vec<(String, bool)>  = vec![];
+        list.push((String::from("hmac-sha1"),true));
+        list.push((String::from("hmac-sha256"),true));
+
+        // se crean las llaves del servidor
+        let key1 = b"1234567890";
+        let key2 = b"1034567692";
+        // se mapean las llaves anteriores a un nombre. Acá deberemos buscar el nombre de lo que se reciba para utilizar la llave correcta
+        let mut keys = HashMap::new();
+        keys.insert(DomainName::new_from_string("nictest.cl".to_string()), key1);
+        keys.insert(DomainName::new_from_string("example.cl".to_string()), key2);
+
+        //se recibiran datos de otro thread a través de un socket UDP
+        let udp_socket = UdpSocket::bind("127.0.0.1:8002").expect("Failed to bind to address");
+        let mut buf = [0; 512];
+        
+        match udp_socket.recv_from(&mut buf) {
+        
+        Ok((size, source)) => {
+                println!("Received {} bytes from {}", size, source);
+                let mut data = DnsMessage::from_bytes(&buf[0..size]).unwrap();
+                println!("The data is {:?}", data);
+                let mut addit = data.get_additional();
+                let rr = addit.pop().expect("No tsigrr");
+                let mut tsig_rd = TSigRdata::new();
+                // let mut can_sign = false;
+
+                match rr.get_rdata() {
+                    Rdata::TSIG(data) =>{
+                        tsig_rd = data;
+                    }
+                    _ => {
+                        //can_sign =  true;
+                        println!("error: no TSIG rdata found!");
+                    }
+                }
+                //se extraen las variables TSIG necesarias.
+                let alg_name = tsig_rd.get_algorithm_name().get_name();
+                let time =tsig_rd.get_time_signed();
+                let fudge = tsig_rd.get_fudge();
+                let mac = tsig_rd.get_mac();
+                let name = rr.get_name();
+                let key_name = name.clone().get_name();
+                // se extrae la llave necesaria
+                let key_found = keys[&name];
+
+                //el servidor verifica la estructura del tsig recibido. Sumamos un pequeño delay al time para simular retraso
+                let (_,error) = process_tsig(&data, key_found, key_name.clone(), time + 50, list, vec![]); 
+                //se setea el aditional sin el ultimo resource record, para que sign_tsig lo regenere
+                data.set_additional(addit);
+                data.update_header_counters();
+                // se firma el mensaje recibido con el digest de la respuesta. Notar que el vector final ahora no está vacío
+                sign_tsig(&mut data, key_found,TsigAlgorithm::from(alg_name),fudge,time, key_name, mac);
+                let response = &DnsMessage::to_bytes(&data);
+                //se verifica que la request haya pasado proces_tsig
+                assert_eq!(error,Rcode::NOERROR);
+                
+                // se envia la respuesta si lo anterior resultó ser correcto
+                udp_socket
+                    .send_to(&response, source)
+                    .expect("Failed to send response");
+                
+            }
+            Err(e) => {
+                eprintln!("Error receiving data: {}", e);
+                
+            }
+        }
+        
+    }
+
+    //Lanzamiento de threads
+    println!("Starting server");
+    let server_handle = thread::spawn(|| {
+        host();  
+        
+    });
+    thread::sleep(Duration::from_secs(2)); 
+
+    // se instancia un socket cliente que enviará y  mensajes
+    let client_sock = UdpSocket::bind("127.0.0.1:8001").expect("Nothing");
+    // El cliente firma el mensaje para enviar al servidor. Se guarda el mac de la firma
+    sign_tsig(&mut dns_query_message, key, alg_name, fudge, time_signed, name.to_string(), vec![]);
+    let mac = dns_query_message.get_mac();
+    let buf = dns_query_message.to_bytes();
+    client_sock.send_to(&buf,"127.0.0.1:8002").unwrap();
+    println!("Mensaje enviado");
+    server_handle.join().unwrap();
+    let mut buf = [0; 512];
+
+    // Ahora el cliente verifica la respuesta recibida del servidor
+    match client_sock.recv_from(&mut buf) {
+        
+        Ok((size, source)) => {
+                println!("Received {} bytes from {}", size, source);
+                let data = DnsMessage::from_bytes(&buf[0..size]).unwrap();
+                println!("The data is {:?}", data);
+
+   
+                // El cliente procesa la respuesta 
+                let (answer, error ) = process_tsig(&data, key, name.to_string(), time_signed, a_algs, mac);
+                // se verifica que el mensaje haya pasado process_tsig
+                assert!(answer);
+                assert_eq!(error,Rcode::NOERROR);
+            }
+            Err(e) => {
+                eprintln!("Error receiving data: {}", e);
+                
+            }
+        }
+
+
+}
+   
\ No newline at end of file
diff --git a/tests/use_case/example_with_bind9/Cargo.toml b/tests/use_case/example_with_bind9/Cargo.toml
new file mode 100644
index 00000000..6242bf72
--- /dev/null
+++ b/tests/use_case/example_with_bind9/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "ej_rust"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+dns_rust = { path="../dns-rust"}
+base64 = "0.22.1"
diff --git a/tests/use_case/example_with_bind9/README.md b/tests/use_case/example_with_bind9/README.md
new file mode 100644
index 00000000..d6c62284
--- /dev/null
+++ b/tests/use_case/example_with_bind9/README.md
@@ -0,0 +1,27 @@
+# Demo TSIG
+Esta es la demo para tsig, es un proxy que retransmite los mensajes a el server, corre con dos pc's en la ip 192.168.100.(2|3)/24, idealmente usen un router y configuren las ip's de manera estatica.
+- cliente es el 100.2, con los puertos 8887 y 8890
+- server es el 100.3
+
+La llave que comparten esta en el archivo llave.key
+
+## recv_dig
+Aqui la demo funciona como un proxy, recive un mensaje del dig, lo procesa y despues recive el mensaje de bind9, lo procesa y lo retransmitee (util para testear si funciona el parseo y la verficacion de tsig)
+
+comando para correr tsig con dig, ejecutar el main y en otra terminal ejecutar
+
+```bash
+dig -p8887 @127.0.0.1 ns1.nictest -k wena.key
+```
+
+Y luego correr el ejemplo
+
+## recv_without_dig
+
+Esto es la demo que se vio en la presentacion. Este genera un mensaje preguntando por ns1.nictest (dominio configurado en bind9) y luego usa las funciones sign y process para verificar el tsig, lo envia, y verifica la respuesta del servidor
+
+Aqui es solo correr el ejemplo
+
+```bash
+cargo run
+```
diff --git a/tests/use_case/example_with_bind9/llave.key b/tests/use_case/example_with_bind9/llave.key
new file mode 100644
index 00000000..054672bd
--- /dev/null
+++ b/tests/use_case/example_with_bind9/llave.key
@@ -0,0 +1,4 @@
+key "WEIRD.NICTEST" {
+	algorithm hmac-sha1;
+	secret "7niAlAtSA70XRNgvlAB5m80ywDA=";
+};
diff --git a/tests/use_case/example_with_bind9/src/main.rs b/tests/use_case/example_with_bind9/src/main.rs
new file mode 100644
index 00000000..442bebd9
--- /dev/null
+++ b/tests/use_case/example_with_bind9/src/main.rs
@@ -0,0 +1,153 @@
+use std::net::UdpSocket;
+use std::time::SystemTime;
+use std::vec;
+use dns_rust::domain_name::DomainName;
+use dns_rust::message::rdata::Rdata;
+use dns_rust::message::DnsMessage;
+use dns_rust::message::{rrtype::Rrtype, rclass::Rclass};
+use dns_rust;
+use base64;
+use base64::Engine as _;
+use dns_rust::tsig::{process_tsig, sign_tsig, TsigAlgorithm};
+use std::io::{stdin, stdout, Write};
+use std::{thread, time};
+
+
+
+pub fn input(prompt: &str) -> String {
+    print!("{}", prompt);
+    let mut input = String::new();
+
+    stdout().flush().expect("Failed to flush stdout!");
+    stdin().read_line(&mut input).expect("Failed to read line");
+
+    input.pop();
+
+    return input;
+}
+const KEY: &[u8; 28] = b"7niAlAtSA70XRNgvlAB5m80ywDA=";
+//const KEY: &[u8; 28] = b"8niAlAtSA70XRNgvlAB5m80ywDA=";
+
+fn generate_tsig_a_query(domain :DomainName, id: u16, key_name: String, key: &[u8]) -> (DnsMessage, Vec<u8>) {
+    let mut dnsmsg = DnsMessage::new_query_message(domain, Rrtype::A, Rclass::IN, 0, true, id);
+    let mut header = dnsmsg.get_header();
+    header.set_ad(true);
+    dnsmsg.set_header(header);
+    let alg_name = TsigAlgorithm::HmacSha1;
+    let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+    let digest = sign_tsig(&mut dnsmsg, key, alg_name, 300, time, key_name, vec![]);
+    return (dnsmsg, digest);
+}
+
+
+fn recv_without_dig(){
+    let three_secs = time::Duration::from_secs(4);
+    
+    let key_bytes = base64::prelude::BASE64_STANDARD.decode(KEY).unwrap();
+    let mut lista_alg = vec![];
+    lista_alg.push((String::from("hmac-sha1"),true));
+    let domain_to_query = DomainName::new_from_str("ns1.nictest");
+    let shared_key_name = "weird.nictest".to_string();
+    let socket_udp = UdpSocket::bind("192.168.100.2:8890").expect("Failed to bind to address");
+    println!("----------------------------------------------------------------");
+    input("Generemos un mensaje con TSIG, presione enter para continuar\n");
+    let (dns_msg, mac) = generate_tsig_a_query(domain_to_query, 6502, shared_key_name.clone(), &key_bytes);
+
+    let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+    let (val, err) = process_tsig(&dns_msg, &key_bytes, shared_key_name.clone(), time, lista_alg.clone(), vec![]);
+    println!("{}", &dns_msg);
+    if !val {
+        println!("Error en la validacion del mensaje");
+        println!("{:?}", err);
+        panic!("Error en la validacion del mensaje");
+    }
+    input("Presione enter para validar la consulta del cliente con tsig");
+    println!("Validacion de la peticion OK! tsig_err {:?}", err);
+    println!("----------------------------------------------------------------");
+    input("Presione enter para enviar el mensaje al servidor");
+    println!("Enviando el mensaje al servidor...");
+    thread::sleep(three_secs);
+    let test_bytes = dns_msg.to_bytes();
+    socket_udp.send_to(&test_bytes, "192.168.100.3:53").unwrap();
+
+    let mut buf = [0; 2000];
+    let (s, _) = socket_udp.recv_from(& mut buf).unwrap();
+    println!("Recibiendo respuesta del servidor\n");
+    let bytes = &buf[0..s].to_vec();
+    let response = DnsMessage::from_bytes(&bytes).expect("Parseo mal!");
+    println!("{}\n", &response);
+    input("Presione enter para validar la respuesta del servidor");
+    let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+    let (val, err) = process_tsig(&response, &key_bytes, shared_key_name.clone(), time, lista_alg, mac);
+    
+    
+    if !val {
+        println!("Error en la validacion del mensaje");
+        println!("tsig_error_code: {:?}", err);
+    }
+    println!("----------------------------------------------------------------");
+}   
+
+fn recv_dig() {
+    let key_bytes = base64::prelude::BASE64_STANDARD.decode(KEY).unwrap();
+    let mut lista_alg = vec![];
+    lista_alg.push((String::from("hmac-sha1"),true));
+
+    let socket_udp = UdpSocket::bind("127.0.0.1:8887").expect("Failed to bind to address");
+    let socket_udp2 = UdpSocket::bind("192.168.100.2:8890").expect("Failed to bind to address");
+    let mut buf = [0;1000];
+    let (s, addr_in) = socket_udp.recv_from(&mut buf).unwrap();
+    //println!("Llego un mensaje de largo {s}");
+    let bytes = &buf[0..s].to_vec();
+    let dnsmsg = DnsMessage::from_bytes(bytes).expect("Parseo mal!");
+
+    let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+    let mac = vec![];
+    let (a, b)= process_tsig(&dnsmsg,  &key_bytes, "weird.nictest".to_string(), time, lista_alg.clone(), mac);
+
+    println!("Verificando la query del cliente!");
+    println!("bool: {:?} tsig_err: {:#?}", a, b);
+    println!("{:#?}",&dnsmsg);
+    println!("-----------------------------------------------------");
+
+    // println!("{:#?}", dnsmsg.get_header());
+    let rrs = dnsmsg.get_additional().pop().unwrap();
+    let tsig = match rrs.get_rdata() {
+        Rdata::TSIG(xd) => {
+            xd
+        },
+        _ => panic!("xd")
+    };
+
+
+    let mac = tsig.get_mac();
+    let test_bytes = dnsmsg.to_bytes();
+
+    socket_udp2.send_to(&test_bytes, "192.168.100.3:53").unwrap();
+
+    let mut buf2 = [0; 2000];
+    let (s2, _) = socket_udp2.recv_from(& mut buf2).unwrap();
+    let bytes2 = &buf2[0..s2].to_vec();
+    let dnsmsg2 = DnsMessage::from_bytes(&bytes2[0..s2]).expect("Parseo mal!");
+
+    // let mut response_dns_tsig_file = File::create("response_tsig_cliente.dns").unwrap();
+    // response_dns_tsig_file.write_all(bytes2).expect("Error al escribir el archivo");
+
+    let parsed_bytes = dnsmsg2.to_bytes();
+
+    socket_udp.send_to(&parsed_bytes, addr_in).unwrap();
+    //process_tsig(&dnsmsg2, key, key_name, time, available_algorithm, mac_to_process)
+
+
+    //panic!();
+    //let bytes = general_purpose::STANDARD.decode(key).unwrap();
+    let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+    let (a, b)= process_tsig(&dnsmsg2,  &key_bytes, "weird.nictest".to_string(), time, lista_alg, mac);
+    println!("Verificando la respuesta del servidor");
+    println!("bool: {:?} tsig_err: {:#?}", a, b);
+}
+
+fn main() {
+    //recv_dig();
+    recv_without_dig()
+}
\ No newline at end of file